TenantAtlas/specs/201-enforcement-review-guardrails/data-model.md

299 lines
24 KiB
Markdown

# Data Model: Enforcement & Review Guardrails
This feature adds repository-owned governance artifacts only. It does not add application database tables, runtime-owned entities, or executable service contracts. All objects below are implemented as markdown guidance, template prompts, checklists, and logical contracts.
Handling modes and review outcome classes are separate concepts in this model. Handling modes describe how a signal or rule is processed in the workflow, while review outcome classes describe the decision reached for a specific change.
## 1. GuardrailRuleMapping
**Purpose**: Maps one Spec 200 or constitution rule family to its operational behavior in review, repository signals, testing, exceptions, and workflow surfaces.
| Field | Type | Description |
|-------|------|-------------|
| `mappingId` | string | Stable identifier for the mapping. |
| `sourceRuleId` | string | Spec 200 or constitution rule family being operationalized. |
| `problemClass` | string | Drift class addressed by the mapping. |
| `operationalClasses` | array | One or more of `review`, `repository-signal`, `test-guardrail`, `exception`, `workflow-touchpoint`. |
| `handlingMode` | string | One of `hard-stop-candidate`, `review-mandatory`, `exception-required`, or `report-only`. |
| `representativeCases` | array | Real repo cases that prove the rule. |
| `targetWorkflowSurfaces` | array | Templates, checklist surfaces, or docs that must express the mapping. |
| `deferredAutomation` | array | Automation or CI work explicitly deferred from the first pass. |
**Validation Rules**
- Every mapping must point to an existing Spec 200 or constitution rule family.
- Every mapping must declare at least one operational class and exactly one first-pass handling mode.
- `hard-stop-candidate` mappings must either have a named exception path or explicitly state `none`.
## 2. ReviewChecklistQuestion
**Purpose**: Represents one mandatory reviewer question used to classify UI and surface work.
| Field | Type | Description |
|-------|------|-------------|
| `questionId` | string | Stable identifier for the review question. |
| `category` | string | `surface-classification`, `native-usage`, `shared-family`, `state-layer`, `exception`, or `test-coverage`. |
| `prompt` | string | The exact decision-grade question. |
| `appliesWhen` | string | Scope rule for when the question must be asked. |
| `linkedMappings` | array | Related `GuardrailRuleMapping` IDs. |
| `evidenceExpected` | string | What the author or reviewer must point to. |
| `defaultOutcomeClass` | string | One of `blocker`, `strong-warning`, `documentation-required-exception`, or `acceptable-special-case`. |
**Validation Rules**
- Questions must be phrased as classification or review-stop decisions, not vague advice.
- Every question must link to at least one guardrail mapping.
- The question set must stay short enough for a representative review pass to complete in under 3 minutes.
## 3. RepositorySignalProfile
**Purpose**: Describes one technically observable red flag that can be reported or escalated during review.
| Field | Type | Description |
|-------|------|-------------|
| `signalId` | string | Stable identifier for the signal. |
| `label` | string | Human-readable signal name. |
| `patternType` | string | `grep`, `search`, `path-pattern`, or `manual`. |
| `searchScopePaths` | array | Paths where the signal applies. |
| `triggerExamples` | array | Observable examples of the pattern. |
| `confidenceLevel` | string | `high`, `medium`, or `low`. |
| `handlingMode` | string | One of `report-only`, `review-mandatory`, `exception-required`, or `hard-stop-candidate`. |
| `exceptionPath` | string | Named exception path or `none`. |
| `futurePromotion` | string | Whether later hardening is allowed and under what condition. |
**Validation Rules**
- Every signal must have a documented handling mode and an exception or review path.
- First-pass automation may not exceed `report-only` unless the signal has high confidence and low ambiguity.
- Signals must stay anchored to real drift cases, not hypothetical future problems.
## 4. TestGuardrailProfile
**Purpose**: Defines the required test and smoke depth for a surface contract class.
| Field | Type | Description |
|-------|------|-------------|
| `profileId` | string | Stable identifier for the surface test profile. |
| `surfaceClass` | string | `shared-detail-family`, `monitoring-state-page`, `global-context-shell`, `exception-coded-surface`, or `standard-native-filament`. |
| `triggers` | array | Conditions that activate the profile. |
| `requiredTestTypes` | array | Required evidence such as `functional-core`, `state-contract`, `exception-fallback`, or `manual-smoke`. |
| `manualSmokeExpectations` | array | Manual review or smoke expectations tied to the profile. |
| `standardCoverageRule` | string | When ordinary feature coverage is enough. |
| `exceptionHandlingRule` | string | How exceptions affect the profile. |
**Validation Rules**
- Every non-standard surface class must declare whether special coverage is mandatory.
- `standard-native-filament` must explicitly state when no additional special guardrail tests are required.
- Profiles must classify by interaction and contract risk, not just by framework or file type.
## 5. ExceptionWorkflowTemplate
**Purpose**: Captures the required fields and checks for a legitimate guardrail exception.
| Field | Type | Description |
|-------|------|-------------|
| `templateId` | string | Stable identifier for the exception template. |
| `exceptionType` | string | Canonical exception type from Spec 200. |
| `brokenRuleIds` | array | Which rule families are being relaxed or not fully satisfied. |
| `requiredFields` | array | Required justification fields the spec or PR must fill. |
| `boundaryChecks` | array | What keeps the exception bounded. |
| `standardizationFields` | array | What remains standardized despite the exception. |
| `spreadReviewRule` | string | What must happen before the exception can extend to new hosts or surfaces. |
| `closeoutNoteTarget` | string | Where the exception must be recorded at completion: the active feature PR close-out entry. |
**Validation Rules**
- Every exception must name the affected rule family and the product reason.
- Boundary checks must be explicit enough to stop silent extension.
- Exception approval is incomplete until the close-out note target is known.
## 6. WorkflowTouchpoint
**Purpose**: Defines one workflow artifact where guardrail behavior must appear.
| Field | Type | Description |
|-------|------|-------------|
| `touchpointId` | string | Stable identifier for the workflow touchpoint. |
| `artifactPath` | string | File path for the workflow surface. |
| `phase` | string | `spec`, `plan`, `tasks`, `review`, `closeout`, or `follow-up`. |
| `requiredPrompts` | array | Questions or fields the artifact must surface. |
| `linkedMappings` | array | Related guardrail mappings. |
| `outcomeTarget` | string | Where the touchpoint records its decision or handoff, including the active feature PR close-out entry when the phase is `closeout`. |
**Validation Rules**
- Every relevant phase from spec to closeout must have at least one touchpoint.
- The active feature PR close-out entry is the single canonical close-out note target for guarded changes.
- The same classification question should not be duplicated unnecessarily across multiple surfaces.
- Touchpoints must point back to existing entry surfaces before any new file is introduced.
## 7. GuardrailAssessment
**Purpose**: Represents the result of classifying one UI or surface change through the workflow.
| Field | Type | Description |
|-------|------|-------------|
| `assessmentId` | string | Stable identifier for one guardrail review. |
| `triggeredMappings` | array | Activated rule mappings. |
| `triggeredSignals` | array | Triggered repository signals, if any. |
| `outcomeClass` | string | `blocker`, `strong-warning`, `documentation-required-exception`, or `acceptable-special-case`. |
| `workflowOutcome` | string | `keep`, `split`, `document-in-feature`, `follow-up-spec`, or `reject-or-split`. |
| `missingEvidence` | array | Missing inputs before the review can close. |
| `recordLocation` | string | Spec, plan, checklist, or the active feature PR close-out entry where the result lives. |
**Validation Rules**
- `blocker` cannot resolve to `keep` while missing evidence remains.
- `documentation-required-exception` requires a completed `ExceptionWorkflowTemplate` entry before the workflow can close as `keep` or `document-in-feature`.
- `recordLocation` must resolve to one declared workflow touchpoint outcome or the active feature PR close-out entry.
- `reject-or-split` is valid when hidden exception spread, unresolved state-layer conflict, or fake-native drift remains uncorrected.
## 8. ValidationScenario
**Purpose**: Represents one scenario used to prove the workflow is both lightweight and effective.
| Field | Type | Description |
|-------|------|-------------|
| `scenarioId` | string | Stable scenario identifier. |
| `scenarioType` | string | `low-impact`, `fake-native`, `shared-family`, `state-layer`, or `legitimate-exception`. |
| `representativeArtifact` | string | Spec, template, or documentation artifact used in the validation walkthrough. |
| `expectedMappings` | array | Rule mappings that should fire. |
| `expectedOutcomeClass` | string | Expected guardrail outcome class. |
| `expectedWorkflowOutcome` | string | Expected workflow outcome. |
| `status` | string | `planned`, `validated`, or `needs-tuning`. |
| `notes` | string | What the scenario proves. |
**Validation Rules**
- At least one `low-impact` and one high-risk scenario must be represented.
- The scenario set must cover fake-native, shared-family, state-layer, and legitimate-exception reasoning.
- Low-impact scenarios must prove that `N/A` paths remain fast and legitimate.
## Relationships
- One `GuardrailRuleMapping` may feed many `ReviewChecklistQuestion`, `RepositorySignalProfile`, and `WorkflowTouchpoint` entries.
- A `RepositorySignalProfile` may trigger a `GuardrailAssessment`, but the final outcome still depends on the associated `ReviewChecklistQuestion` and any `ExceptionWorkflowTemplate`.
- One `TestGuardrailProfile` may be referenced by many `GuardrailRuleMapping` entries when multiple rule families converge on the same surface class.
- One `ExceptionWorkflowTemplate` may be required by many `GuardrailAssessment` records, but each assessment must keep its own bounded record location.
- `ValidationScenario` objects prove that the combined model stays usable across both low-friction and high-risk cases.
## State Transitions
### GuardrailAssessment.workflowOutcome
- `keep` -> `document-in-feature`: allowed when a change is valid but the active feature still needs to record exception or signal handling explicitly.
- `document-in-feature` -> `follow-up-spec`: allowed when review shows the issue is structural, recurring, or likely to need harder automation.
- Any state -> `reject-or-split`: allowed when fake-native drift, hidden exception spread, unresolved host drift, or unresolved state-layer collapse remains.
### ValidationScenario.status
- `planned` -> `validated`: allowed when the workflow can classify the scenario with the expected outcome and without extra categories.
- `planned` -> `needs-tuning`: allowed when wording is ambiguous, repetitive, or too heavy for the scenario.
- `needs-tuning` -> `validated`: allowed after the relevant template, checklist, or guidance text is refined.
## Derived Outputs
The conceptual model must support these concrete outputs:
- a guardrail catalog that maps Spec 200 rule families to operational behavior
- a reviewer question set with fixed outcome classes
- a repository signal catalog with handling modes and exception escape paths
- a surface-class test guardrail matrix
- an exception workflow template with spread-control rules
- workflow touchpoint changes in the spec, plan, task, checklist, and close-out surfaces
- validation scenarios that prove both low-impact and high-risk usability
## Canonical Implementation Snapshot
### GuardrailRuleMapping Records
| `mappingId` | `sourceRuleId` | `problemClass` | `operationalClasses` | `handlingMode` | `representativeCases` | `targetWorkflowSurfaces` | `deferredAutomation` |
|---|---|---|---|---|---|---|---|
| `GRM-001` | `UI-FIL-001`, `UI-HARD-001` | `fake-native-core-control` | `review`, `repository-signal`, `workflow-touchpoint` | `hard-stop-candidate` | Spec 196 fake-native cleanups | `spec-template`, `checklist-template`, `tasks-template`, `.specify/README.md` | `CI hard-stop deferred`, `grep remains report-first` |
| `GRM-002` | `UI-REVIEW-001`, `UI-EX-001` | `shared-family-host-drift` | `review`, `test-guardrail`, `exception`, `workflow-touchpoint` | `review-mandatory` | Spec 197 shared detail contract | `spec-template`, `plan-template`, `checklist-template`, `tasks-template` | `family linting deferred` |
| `GRM-003` | `DECIDE-001`, `OPSURF-001`, `UI-REVIEW-001` | `state-layer-ownership-collapse` | `review`, `repository-signal`, `test-guardrail`, `workflow-touchpoint` | `review-mandatory` | Specs 198 and 199 state-layer cases | `spec-template`, `plan-template`, `checklist-template`, `tasks-template` | `state-owner grep deferred` |
| `GRM-004` | `UI-EX-001`, `UI-FIL-001` | `bounded-custom-surface-exception` | `review`, `exception`, `test-guardrail`, `workflow-touchpoint` | `exception-required` | Spec 200 legitimate special-case model | `spec-template`, `plan-template`, `checklist-template`, `.specify/README.md` | `exception bot deferred` |
| `GRM-005` | `TEST-TRUTH-001`, `UI-FIL-001` | `standard-native-surface-relief` | `test-guardrail`, `workflow-touchpoint` | `report-only` | Standard native Filament work with no special contract | `plan-template`, `tasks-template`, `checklist-template` | `auto-relief detection deferred` |
### ReviewChecklistQuestion Records
| `questionId` | `category` | `prompt` | `appliesWhen` | `linkedMappings` | `evidenceExpected` | `defaultOutcomeClass` |
|---|---|---|---|---|---|---|
| `CHK-SURF-001` | `surface-classification` | Does the change clearly state whether an operator-facing or guardrailed workflow surface is affected, or does it use one valid low-impact `N/A` path? | Always | `GRM-001`, `GRM-005` | Spec guardrail impact block | `acceptable-special-case` |
| `CHK-NATIVE-001` | `native-usage` | Does the surface stay native/shared-primitives first, or is a custom surface claim being made explicitly? | Operator-facing surface changes | `GRM-001`, `GRM-004` | Surface classification, planned primitives, review notes | `blocker` |
| `CHK-SHARED-001` | `shared-family` | If the surface belongs to a shared family, is the host/core boundary still one shared contract rather than a quiet fork? | Shared family or repeated micro-UI | `GRM-002` | Shared-family note, host variation description | `strong-warning` |
| `CHK-STATE-001` | `state-layer` | Are shell, page, detail, and URL/query state owners named once and kept separate? | Shell, monitoring, stateful surfaces | `GRM-003` | State-layer summary in spec/plan | `strong-warning` |
| `CHK-EXC-001` | `exception` | If default rules are intentionally relaxed, is there a bounded exception with spread control and a named close-out target? | Custom surface or rule relaxation | `GRM-004` | Exception record and close-out note target | `documentation-required-exception` |
| `CHK-TEST-001` | `test-coverage` | Does the surface class use the right special profile, or explicit `standard-native-filament` relief? | Runtime or UI-surface changes | `GRM-002`, `GRM-003`, `GRM-004`, `GRM-005` | Test profile, manual smoke, validation commands | `strong-warning` |
### RepositorySignalProfile Records
| `signalId` | `label` | `patternType` | `searchScopePaths` | `triggerExamples` | `confidenceLevel` | `handlingMode` | `exceptionPath` | `futurePromotion` |
|---|---|---|---|---|---|---|---|---|
| `SIG-001` | `fake-native-control` | `grep` | `app/Filament/**`, `resources/views/**` | Plain buttons or custom surface controls replacing native Filament semantics | `high` | `hard-stop-candidate` | `bounded-custom-surface-exception` | Hard-stop only after report-first validation stays low-noise |
| `SIG-002` | `request-driven-page-state` | `grep` | `app/Filament/**`, `resources/views/**` | GET-form or request/query state driving page-body UI outside documented filter/shell patterns | `high` | `review-mandatory` | `none` | Promote only with later noise review |
| `SIG-003` | `shared-family-host-fork` | `path-pattern` | `app/Filament/**`, `resources/views/**`, `docs/ui/**` | New host-specific partial or duplicated shared-family markup | `medium` | `review-mandatory` | `bounded-custom-surface-exception` | Future linting stays deferred |
| `SIG-004` | `shell-context-leak` | `search` | `app/Filament/**`, `resources/views/**` | Workspace or tenant resolution logic leaks into presentation partials | `medium` | `review-mandatory` | `none` | Report-first only in this rollout |
| `SIG-005` | `simple-overview-customization` | `manual` | `app/Filament/**`, `resources/views/**` | Hand-rolled overview/status UI where native widgets or shared primitives should remain primary | `medium` | `report-only` | `bounded-custom-surface-exception` | Never auto-block in first pass |
### TestGuardrailProfile Records
| `profileId` | `surfaceClass` | `triggers` | `requiredTestTypes` | `manualSmokeExpectations` | `standardCoverageRule` | `exceptionHandlingRule` |
|---|---|---|---|---|---|---|
| `TGP-001` | `standard-native-filament` | Standard Resource/Page/RelationManager with no special shared, shell, or exception contract | none beyond ordinary feature coverage | Optional ordinary UI smoke only | Ordinary feature coverage is sufficient | If a later exception appears, switch to `exception-coded-surface` |
| `TGP-002` | `shared-detail-family` | Reused detail micro-UI shared across multiple hosts | `functional-core` | Verify one representative host and the host/core boundary | Extra bespoke tests stay off unless the family contract changes | Host-specific divergence activates exception review |
| `TGP-003` | `monitoring-state-page` | Monitoring or governance page owns its own state contract | `functional-core`, `state-contract` | Verify empty, loaded, and conflict states | Use the narrowest honest non-browser lane first | Local exception paths require explicit fallback coverage |
| `TGP-004` | `global-context-shell` | Shell or context-recovery logic is changed | `state-contract`, `exception-fallback` | Verify valid, invalid, and recovery/fallback states | No extra browser family by default | Context exceptions require bounded fallback proof |
| `TGP-005` | `exception-coded-surface` | Legitimate custom or special visualization relaxes a default rule | `functional-core`, `exception-fallback`, `manual-smoke` | Verify bounded exception behavior and preserved standardized parts | `standard-native-filament` relief does not apply | Close-out must justify the exception and the proof depth |
### ExceptionWorkflowTemplate Record
| `templateId` | `exceptionType` | `brokenRuleIds` | `requiredFields` | `boundaryChecks` | `standardizationFields` | `spreadReviewRule` | `closeoutNoteTarget` |
|---|---|---|---|---|---|---|---|
| `EXW-001` | `bounded-custom-surface-exception` | `UI-FIL-001`, `UI-EX-001`, `UI-REVIEW-001` as applicable | Broken rule IDs, product reason, bounded surface/host, preserved standardized parts, required tests/manual smoke, deferred automation, active close-out note | No silent reuse on new hosts, no new helper spread without review, no alternate state owner introduced implicitly | Canonical noun, primary operator action, inspect model, standardized parts still preserved | Any extension to a new host, route, or surface requires renewed explicit review | Active feature PR close-out entry `Guardrail / Exception / Smoke Coverage` |
### WorkflowTouchpoint Records
| `touchpointId` | `artifactPath` | `phase` | `requiredPrompts` | `linkedMappings` | `outcomeTarget` |
|---|---|---|---|---|---|
| `WTP-001` | `.specify/templates/spec-template.md` | `spec` | UI / Surface Guardrail Impact block, low-impact `N/A` rule | `GRM-001`, `GRM-002`, `GRM-003`, `GRM-004` | `.specify/templates/plan-template.md` |
| `WTP-002` | `.specify/templates/plan-template.md` | `plan` | Handling modes, repository-signal treatment, test profiles, close-out entry | `GRM-002`, `GRM-003`, `GRM-004`, `GRM-005` | `.specify/templates/tasks-template.md` |
| `WTP-003` | `.specify/templates/tasks-template.md` | `tasks` | Carry-forward classification, proof tasks, exception documentation, close-out task | `GRM-001`, `GRM-002`, `GRM-003`, `GRM-004`, `GRM-005` | `.specify/templates/checklist-template.md` |
| `WTP-004` | `.specify/templates/checklist-template.md` | `review` | Fixed reviewer questions, outcome class, workflow outcome | `GRM-001`, `GRM-002`, `GRM-003`, `GRM-004`, `GRM-005` | Active feature PR close-out entry |
| `WTP-005` | `.specify/README.md` | `follow-up` | Author entry, review entry, low-impact rule, escalation rule, close-out rule | `GRM-001`, `GRM-004`, `GRM-005` | Active feature PR close-out entry |
| `WTP-006` | `active feature PR close-out entry` | `closeout` | Scenario used, outcome class, handling mode, workflow outcome, proof depth, exception boundary, deferred automation | `GRM-002`, `GRM-003`, `GRM-004`, `GRM-005` | `Guardrail / Exception / Smoke Coverage` |
### ValidationScenario Records
| `scenarioId` | `scenarioType` | `representativeArtifact` | `expectedMappings` | `expectedOutcomeClass` | `expectedWorkflowOutcome` | `status` | `notes` |
|---|---|---|---|---|---|---|---|
| `VAL-001` | `low-impact` | `.specify/templates/checklist-template.md` + `.specify/README.md` wording-only path | `GRM-005` | `acceptable-special-case` | `keep` | `validated` | Low-impact path stayed under one minute and used one `N/A` note only |
| `VAL-002` | `fake-native` | `specs/196-hard-filament-nativity-cleanup/spec.md` | `GRM-001` | `blocker` | `reject-or-split` | `validated` | Fake-native drift remained the hardest signal |
| `VAL-003` | `shared-family` | `specs/197-shared-detail-contract/spec.md` | `GRM-002` | `strong-warning` | `document-in-feature` | `validated` | Shared-family boundary still needs explicit reviewer judgment |
| `VAL-004` | `state-layer` | `specs/198-monitoring-page-state/spec.md` + `specs/199-global-context-shell-contract/spec.md` | `GRM-003` | `strong-warning` | `document-in-feature` | `validated` | State-owner naming is mandatory before merge |
| `VAL-005` | `legitimate-exception` | `specs/200-filament-surface-rules/spec.md` | `GRM-004` | `documentation-required-exception` | `document-in-feature` | `validated` | Legitimate special cases stay allowed only with bounded exception notes |
### Active Feature PR Close-out Entry
| Field | Requirement |
|---|---|
| `entryName` | `Guardrail / Exception / Smoke Coverage` |
| `scenarioUsed` | Low-impact or representative guarded scenario used for validation |
| `outcomeClass` | One of `blocker`, `strong-warning`, `documentation-required-exception`, or `acceptable-special-case` |
| `handlingMode` | One of `hard-stop-candidate`, `review-mandatory`, `exception-required`, or `report-only` |
| `workflowOutcome` | One of `keep`, `split`, `document-in-feature`, `follow-up-spec`, or `reject-or-split` |
| `proofDepth` | Required tests or manual smoke, or explicit `standard-native-filament` relief |
| `exceptionBoundary` | `N/A` for low-impact or standard-native work, otherwise the bounded exception summary |
| `duplicatePromptNotes` | Whether any classification question still appeared redundantly across workflow surfaces |
| `deferredAutomation` | Any grep/lint/CI hardening explicitly deferred in the first pass |
## Out of Scope
- database tables
- Eloquent models or services
- CI bots or grep scripts as implementation deliverables
- runtime Livewire or Filament classes
- public HTTP or CLI APIs
- a new top-level handbook outside existing `.specify/` workflow surfaces