Automated PR provided by Codex via Gitea API. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #476
332 lines
27 KiB
Markdown
332 lines
27 KiB
Markdown
# Spec 405 Implementation Report - JSON-to-JSONB Data-layer Hardening
|
|
|
|
## 1. Candidate Gate Result
|
|
|
|
**Current result**: `PASS WITH CONDITIONS`.
|
|
|
|
Local PostgreSQL migration/type proof, rollback/down-up proof, schema-attribute proof, and focused model/query regression tests pass. The remaining condition is external staging/Dokploy validation; it is not accessible from this agent session, so the gate cannot honestly be stronger than `PASS WITH CONDITIONS`.
|
|
|
|
## 2. Scope Confirmation
|
|
|
|
In scope:
|
|
|
|
- Inventory every live PostgreSQL `json` and `jsonb` column.
|
|
- Classify every live `json` column.
|
|
- Convert only reviewed `CONVERT` columns to `jsonb`.
|
|
- Preserve current payload semantics, casts, scoping, and query behavior.
|
|
- Add local PostgreSQL tests and focused regression proof.
|
|
|
|
Out of scope and not changed:
|
|
|
|
- UI surfaces, routes, navigation, Filament resources, panels, actions, forms, tables, widgets, or customer output.
|
|
- Authorization model, roles, capabilities, provider semantics, lifecycle semantics, normalized replacement tables, and new product concepts.
|
|
- Completed historical specs and their validation/task/smoke/browser history.
|
|
- Speculative JSONB indexes.
|
|
|
|
Historical context reviewed as read-only:
|
|
|
|
- Spec 400: no `implementation-report.md` present; spec/plan/tasks were treated as historical audit context only.
|
|
- Spec 401: backup confirmation and provider residual context reviewed; left unchanged.
|
|
- Spec 402: provider action residual closure context reviewed; left unchanged.
|
|
- Spec 403: evidence/currentness runtime closure context reviewed; left unchanged.
|
|
- Spec 404: management report PDF staging validation and `PASS WITH CONDITIONS` staging caveat reviewed; left unchanged.
|
|
|
|
## 3. Dirty State
|
|
|
|
Initial repository state:
|
|
|
|
- Branch: `405-json-to-jsonb-data-layer-hardening`
|
|
- HEAD: `8918b357 feat: finish management report PDF staging validation (#475)`
|
|
- Initial dirty state: untracked `specs/405-json-to-jsonb-data-layer-hardening/`
|
|
- Session branch not created because the active spec package was already untracked in the working tree; work continued cautiously on the current feature branch.
|
|
- Initial `git diff --check`: passed.
|
|
|
|
Final `git status --short --untracked-files=all`:
|
|
|
|
```text
|
|
M apps/platform/app/Models/BackupItem.php
|
|
?? apps/platform/database/migrations/2026_06_23_000405_convert_trust_payload_json_columns_to_jsonb.php
|
|
?? apps/platform/tests/Feature/Database/JsonbDataLayerHardeningTest.php
|
|
?? specs/405-json-to-jsonb-data-layer-hardening/checklists/requirements.md
|
|
?? specs/405-json-to-jsonb-data-layer-hardening/implementation-report.md
|
|
?? specs/405-json-to-jsonb-data-layer-hardening/plan.md
|
|
?? specs/405-json-to-jsonb-data-layer-hardening/spec.md
|
|
?? specs/405-json-to-jsonb-data-layer-hardening/tasks.md
|
|
```
|
|
|
|
The spec package was untracked at session start. This implementation added the migration, database test, implementation report, task completion updates, and the `BackupItem` runtime adjustment.
|
|
|
|
## 4. JSON/JSONB Inventory Matrix
|
|
|
|
Inventory source: PostgreSQL `information_schema.columns`, row/null counts from the live local database, 2026-06-23. Converted-column migration decision is direct `ALTER COLUMN ... TYPE jsonb USING ...::jsonb`, grouped per table when more than one column is converted on the same table. Local converted tables have small row counts and no JSON-column index rebuild requirement; staging must still validate actual lock duration and migration runtime before production promotion.
|
|
|
|
| Column | Type | Rows | Nulls | Nullable | Default | Indexes | Classification | Decision |
|
|
|---|---:|---:|---:|---|---|---|---|---|
|
|
| alert_deliveries.payload | json | 0 | 0 | YES | none | none | CONVERT P2 | Alert delivery payload; direct conversion. |
|
|
| alert_rules.tenant_allowlist | json | 0 | 0 | YES | none | none | CONVERT P2 | Alert scoping list; direct conversion. |
|
|
| audit_logs.metadata | json | 1320 | 0 | YES | none | none | CONVERT P1 | Audit context queried by metadata key; direct conversion. |
|
|
| backup_items.payload | json | 246 | 0 | NO | none | none | CONVERT P1 | Critical backup snapshot payload; direct conversion. |
|
|
| backup_items.metadata | json | 246 | 0 | YES | none | none | CONVERT P1 | Backup metadata and warnings; direct conversion. |
|
|
| backup_items.assignments | json | 246 | 146 | YES | none | none | CONVERT P1 | Assignment proof payload; direct conversion and query function update. |
|
|
| backup_schedules.days_of_week | json | 0 | 0 | YES | none | none | CONVERT P2 | Schedule structured config; direct conversion. |
|
|
| backup_schedules.policy_types | json | 0 | 0 | NO | none | none | CONVERT P2 | Schedule policy-type filter; direct conversion. |
|
|
| backup_sets.metadata | json | 25 | 0 | YES | none | none | CONVERT P1 | Backup-set provenance metadata; direct conversion. |
|
|
| baseline_profiles.scope_jsonb | jsonb | 4 | 0 | NO | none | none | ALREADY_JSONB | No migration. |
|
|
| baseline_snapshot_items.meta_jsonb | jsonb | 102 | 0 | YES | none | none | ALREADY_JSONB | No migration. |
|
|
| baseline_snapshots.summary_jsonb | jsonb | 4 | 0 | YES | none | none | ALREADY_JSONB | No migration. |
|
|
| baseline_snapshots.completion_meta_jsonb | jsonb | 4 | 0 | YES | none | none | ALREADY_JSONB | No migration. |
|
|
| baseline_tenant_assignments.override_scope_jsonb | jsonb | 3 | 3 | YES | none | none | ALREADY_JSONB | No migration. |
|
|
| entra_groups.group_types | jsonb | 574 | 0 | YES | none | none | ALREADY_JSONB | No migration. |
|
|
| environment_review_sections.summary_payload | jsonb | 153 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| environment_review_sections.render_payload | jsonb | 153 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| environment_reviews.summary | jsonb | 28 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| evidence_snapshot_items.summary_payload | jsonb | 98 | 0 | NO | `{}` | `evidence_snapshot_items_payload_gin` | ALREADY_JSONB | Existing justified GIN retained. |
|
|
| evidence_snapshots.summary | jsonb | 24 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| finding_exception_decisions.metadata | jsonb | 7 | 0 | NO | `{}` | `finding_exception_decisions_metadata_gin` | ALREADY_JSONB | Existing justified GIN retained. |
|
|
| finding_exception_evidence_references.summary_payload | jsonb | 0 | 0 | NO | `{}` | `finding_exception_evidence_refs_payload_gin` | ALREADY_JSONB | Existing justified GIN retained. |
|
|
| finding_exceptions.evidence_summary | jsonb | 9 | 0 | NO | `{}` | `finding_exceptions_evidence_summary_gin` | ALREADY_JSONB | Existing justified GIN retained. |
|
|
| findings.evidence_jsonb | jsonb | 254 | 0 | YES | none | none | ALREADY_JSONB | No migration. |
|
|
| inventory_items.meta_jsonb | jsonb | 229 | 0 | YES | none | none | ALREADY_JSONB | No migration. |
|
|
| inventory_links.metadata | jsonb | 251 | 0 | YES | none | none | ALREADY_JSONB | No migration. |
|
|
| managed_environment_onboarding_sessions.state | json | 2 | 0 | YES | none | none | CONVERT P1 | Onboarding state payload; direct conversion. |
|
|
| managed_environment_permissions.details | json | 135 | 0 | YES | none | none | CONVERT P1 | Provider permission details; direct conversion. |
|
|
| managed_environment_triage_reviews.review_snapshot | jsonb | 0 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| managed_environments.metadata | json | 54 | 2 | YES | none | none | CONVERT P1 | Provider/environment metadata; direct conversion. |
|
|
| managed_environments.rbac_canary_results | json | 54 | 54 | YES | none | none | CONVERT P1 | RBAC readiness proof; direct conversion. |
|
|
| managed_environments.rbac_last_warnings | json | 54 | 54 | YES | none | none | CONVERT P1 | RBAC warning proof; direct conversion. |
|
|
| notifications.data | jsonb | 311 | 0 | NO | none | none | ALREADY_JSONB | No migration. |
|
|
| operation_runs.summary_counts | jsonb | 96 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| operation_runs.failure_summary | jsonb | 96 | 0 | NO | `[]` | none | ALREADY_JSONB | No migration. |
|
|
| operation_runs.context | jsonb | 96 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| platform_users.capabilities | jsonb | 1 | 0 | NO | `[]` | none | ALREADY_JSONB | No migration. |
|
|
| policies.metadata | json | 208 | 3 | YES | none | none | CONVERT P1 | Policy inventory metadata; direct conversion. |
|
|
| policy_versions.snapshot | json | 422 | 0 | NO | none | none | CONVERT P1 | Immutable policy snapshot; direct conversion. |
|
|
| policy_versions.metadata | json | 422 | 0 | YES | none | none | CONVERT P1 | Version metadata; direct conversion. |
|
|
| policy_versions.assignments | json | 422 | 216 | YES | none | none | CONVERT P1 | Version assignment snapshot; direct conversion. |
|
|
| policy_versions.scope_tags | json | 422 | 14 | YES | none | none | CONVERT P1 | Scope tag snapshot; direct conversion. |
|
|
| policy_versions.secret_fingerprints | json | 422 | 2 | YES | none | none | CONVERT P1 | Redaction integrity metadata; direct conversion. |
|
|
| product_usage_events.metadata | jsonb | 100 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| provider_connections.scopes_granted | jsonb | 16 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| provider_connections.metadata | jsonb | 16 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| restore_runs.requested_items | json | 4 | 2 | YES | none | none | CONVERT P1 | Restore request payload; direct conversion. |
|
|
| restore_runs.preview | json | 4 | 1 | YES | none | none | CONVERT P1 | Restore preview payload; direct conversion. |
|
|
| restore_runs.results | json | 4 | 0 | YES | none | none | CONVERT P1 | Restore execution result payload; direct conversion. |
|
|
| restore_runs.metadata | json | 4 | 0 | YES | none | none | CONVERT P1 | Restore metadata; direct conversion. |
|
|
| restore_runs.group_mapping | json | 4 | 4 | YES | none | none | CONVERT P1 | Restore group mapping; direct conversion. |
|
|
| review_packs.summary | jsonb | 23 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| review_packs.options | jsonb | 23 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| review_publication_resolution_cases.summary | jsonb | 3 | 0 | NO | `{}` | `review_publication_resolution_cases_summary_gin` | ALREADY_JSONB | Existing justified GIN retained. |
|
|
| review_publication_resolution_cases.metadata | jsonb | 3 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| review_publication_resolution_steps.summary | jsonb | 17 | 0 | NO | `{}` | `review_publication_resolution_steps_summary_gin` | ALREADY_JSONB | Existing justified GIN retained. |
|
|
| review_publication_resolution_steps.metadata | jsonb | 17 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| settings_catalog_definitions.raw | jsonb | 0 | 0 | NO | none | `idx_settings_catalog_definitions_raw_gin` | ALREADY_JSONB | Existing justified GIN retained. |
|
|
| stored_reports.payload | jsonb | 35 | 0 | NO | none | `stored_reports_payload_gin` | ALREADY_JSONB | Existing justified GIN retained. |
|
|
| support_requests.context_envelope | jsonb | 0 | 0 | NO | `{}` | none | ALREADY_JSONB | No migration. |
|
|
| tenant_settings.value | json | 0 | 0 | NO | none | none | CONVERT P1 | Tenant-scoped setting value; direct conversion. |
|
|
| workspace_settings.value | json | 0 | 0 | NO | none | none | CONVERT P1 | Workspace-scoped setting value; direct conversion. |
|
|
|
|
No live `json` column was left as `KEEP_JSON`, `DEPRECATED`, or `DECISION_REQUIRED`: every live `json` column had current model ownership, bounded row counts, existing cast/read semantics, and a trust-layer storage reason to align with the existing `jsonb` baseline.
|
|
|
|
Inventory ownership, cast, and query continuation for converted columns:
|
|
|
|
| Column | Model / owner | Existing cast or accessor | Existing query/rendered usage | Constraint/FK context |
|
|
|---|---|---|---|---|
|
|
| alert_deliveries.payload | `App\Models\AlertDelivery` | `array` | Alert delivery rendering/notification payload; no JSON predicate. | Workspace/environment/rule/destination FKs unchanged. |
|
|
| alert_rules.tenant_allowlist | `App\Models\AlertRule` | `array` | Alert tenant scoping list; no JSON predicate. | Workspace FK unchanged. |
|
|
| audit_logs.metadata | `App\Models\AuditLog` / `AuditRecorder` | `array` | `metadata ->> '_dedupe_key'`, `metadata->...` audit filters/tests. | Workspace/environment/operation FKs and audit scope check unchanged. |
|
|
| backup_items.payload | `App\Models\BackupItem` | `array` | Backup set detail, restore readiness, included item rendering. | Workspace/environment/backup/policy FKs unchanged. |
|
|
| backup_items.metadata | `App\Models\BackupItem` | `array` | Backup quality/source/warning helpers and rendered backup detail. | Workspace/environment/backup/policy FKs unchanged. |
|
|
| backup_items.assignments | `App\Models\BackupItem` | `array` | `scopeWithAssignments()`; assignment count/group helper rendering. | Workspace/environment/backup/policy FKs unchanged. |
|
|
| backup_schedules.days_of_week | `App\Models\BackupSchedule` | `array` | Schedule form/detail semantics; no JSON predicate. | Workspace/environment FKs and frequency check unchanged. |
|
|
| backup_schedules.policy_types | `App\Models\BackupSchedule` | `array` | Schedule policy-type selection; no JSON predicate. | Workspace/environment FKs and frequency check unchanged. |
|
|
| backup_sets.metadata | `App\Models\BackupSet` | `array` | Backup provenance/source helpers; `metadata->source` test path. | Workspace/environment FK unchanged. |
|
|
| managed_environment_onboarding_sessions.state | `App\Models\ManagedEnvironmentOnboardingSession` | `array` with allowed-key mutator | Onboarding resume/state rendering and historical migration reads. | Workspace/environment/user FKs and lifecycle constraints unchanged. |
|
|
| managed_environment_permissions.details | `App\Models\ManagedEnvironmentPermission` | `array` | Provider permission/readiness detail rendering; no JSON predicate. | Workspace/environment FK and permission unique key unchanged. |
|
|
| managed_environments.metadata | `App\Models\ManagedEnvironment` | `array` | Environment/provider metadata accessors and rendered environment context. | Workspace FK and tenant lifecycle constraints unchanged. |
|
|
| managed_environments.rbac_canary_results | `App\Models\ManagedEnvironment` | JSON decode accessor | RBAC readiness proof rendering. | Workspace FK and tenant lifecycle constraints unchanged. |
|
|
| managed_environments.rbac_last_warnings | `App\Models\ManagedEnvironment` | JSON decode accessor | RBAC warning rendering. | Workspace FK and tenant lifecycle constraints unchanged. |
|
|
| policies.metadata | `App\Models\Policy` | `array` | Policy inventory metadata rendering and helper access. | Workspace/environment FK unchanged. |
|
|
| policy_versions.snapshot | `App\Models\PolicyVersion` | `array` | Immutable version snapshot rendering/diff/backup provenance. | Workspace/environment/policy FKs unchanged. |
|
|
| policy_versions.metadata | `App\Models\PolicyVersion` | `array` | Version source/warning/integrity helpers. | Workspace/environment/policy FKs unchanged. |
|
|
| policy_versions.assignments | `App\Models\PolicyVersion` | `array` | Version assignment snapshot rendering; sibling hash index unchanged. | Workspace/environment/policy FKs unchanged. |
|
|
| policy_versions.scope_tags | `App\Models\PolicyVersion` | `array` | Scope tag snapshot rendering; sibling hash index unchanged. | Workspace/environment/policy FKs unchanged. |
|
|
| policy_versions.secret_fingerprints | `App\Models\PolicyVersion` | `array` | Redaction integrity helper. | Workspace/environment/policy FKs unchanged. |
|
|
| restore_runs.requested_items | `App\Models\RestoreRun` | `array` | Restore request/preview detail rendering. | Workspace/environment/backup FKs unchanged. |
|
|
| restore_runs.preview | `App\Models\RestoreRun` | `array` | Restore preview wizard/detail rendering. | Workspace/environment/backup FKs unchanged. |
|
|
| restore_runs.results | `App\Models\RestoreRun` | `array` | Restore result proof/detail rendering. | Workspace/environment/backup FKs unchanged. |
|
|
| restore_runs.metadata | `App\Models\RestoreRun` | `array` | Restore result/safety metadata and reconciliation helpers; no direct JSON predicate on this table. | Workspace/environment/backup FKs unchanged. |
|
|
| restore_runs.group_mapping | `App\Models\RestoreRun` | `array` | Restore group-mapping preview/detail rendering. | Workspace/environment/backup FKs unchanged. |
|
|
| tenant_settings.value | `App\Models\TenantSetting` | `array` | Tenant settings read/write; no JSON predicate. | Workspace/environment/user FKs unchanged. |
|
|
| workspace_settings.value | `App\Models\WorkspaceSetting` | `array` | Workspace settings read/write; no JSON predicate. | Workspace/user FKs unchanged. |
|
|
|
|
Already-JSONB ownership groups were also reviewed and left unchanged:
|
|
|
|
- Baseline/inventory/finding/evidence/review rows: existing `*_jsonb`, `summary`, `summary_payload`, `render_payload`, `meta_jsonb`, and evidence payload columns with current model/service ownership; existing GIN indexes retained where already present.
|
|
- OperationRun/provider/notification/support rows: existing `operation_runs.context`, summary/failure payloads, provider connection metadata/scopes, notification data, product usage metadata, and support request context already use `jsonb`.
|
|
- Stored report and review publication rows: `stored_reports.payload`, review pack summaries/options, and review publication resolution summaries/metadata already use `jsonb`; browser proof confirms rendered output remains stable.
|
|
|
|
## 5. Migrations Added
|
|
|
|
Added `apps/platform/database/migrations/2026_06_23_000405_convert_trust_payload_json_columns_to_jsonb.php`.
|
|
|
|
- Converts the 27 reviewed `CONVERT` columns with `ALTER TABLE ... ALTER COLUMN ... TYPE jsonb USING column::jsonb`.
|
|
- Groups multiple converted columns on the same table into a single `ALTER TABLE` statement to avoid repeated per-column table rewrites/lock windows where PostgreSQL can satisfy the changes together.
|
|
- Runs only when `DB::getDriverName() === 'pgsql'`.
|
|
- Preserves nullability, defaults, constraints, and existing non-JSON indexes by altering only the column type.
|
|
- Rollback converts the same columns back to `json` with `USING column::json`.
|
|
- Rollback limitation: `jsonb` canonicalizes object key ordering and duplicate JSON object keys. Semantic content is preserved, but byte-for-byte textual JSON representation is not guaranteed.
|
|
- Local rollback/down-up proof passed in the PostgreSQL lane, including `BackupItem::withAssignments()` while the column is temporarily `json`.
|
|
|
|
## 6. Index Justification
|
|
|
|
No new JSONB indexes were added.
|
|
|
|
Usage scan found one conversion-affected raw JSON function path, `BackupItem::scopeWithAssignments()`, which filters by array length but does not justify a GIN or expression index at current row counts. Existing hash/sibling indexes and existing GIN indexes on already-JSONB tables remain unchanged.
|
|
|
|
The new PostgreSQL test asserts no speculative GIN index exists on converted-column tables.
|
|
|
|
## 7. Runtime Changes Made
|
|
|
|
Changed `apps/platform/app/Models/BackupItem.php`:
|
|
|
|
- `scopeWithAssignments()` now uses `jsonb_array_length(assignments::jsonb)` on PostgreSQL.
|
|
- The explicit cast keeps the scope compatible during pre-migration deploy windows and after a database-only rollback to `json`.
|
|
- Non-PostgreSQL test lanes keep `json_array_length(assignments)` to avoid breaking SQLite-style JSON test support.
|
|
|
|
No model casts required changes. Laravel array casts continue to read/write `jsonb` columns correctly.
|
|
|
|
## 8. Tests Added or Updated
|
|
|
|
Added `apps/platform/tests/Feature/Database/JsonbDataLayerHardeningTest.php` with PostgreSQL-only coverage:
|
|
|
|
- All reviewed legacy `json` columns are `jsonb` after migrations.
|
|
- The 405 migration can run `down()` to `json` and back `up()` to `jsonb` while preserving representative existing rows.
|
|
- Nullability, defaults, table indexes, and constraints remain unchanged across the 405 down/up cycle.
|
|
- No remaining live public-schema `json` columns remain after the conversion migration.
|
|
- No speculative GIN index was introduced for converted columns.
|
|
- Representative read/write/cast behavior for alert, audit, backup, restore, policy, provider/environment, settings, and onboarding payload categories.
|
|
- Audit metadata key query using `metadata ->> '_dedupe_key'`.
|
|
- `BackupItem::withAssignments()` query path against both rollback-state `json` and migrated `jsonb`.
|
|
|
|
Latest result: 5 tests passed, 260 assertions.
|
|
|
|
Existing test run:
|
|
|
|
- `apps/platform/tests/Unit/BackupItemTest.php` still passes after the driver-aware scope change.
|
|
- Latest result: 20 tests passed, 31 assertions.
|
|
|
|
## 9. Data Validation
|
|
|
|
Local PostgreSQL validation:
|
|
|
|
- The migration/type test ran migrations on the PostgreSQL testing database and asserted every converted column is `jsonb`.
|
|
- The new down/up test temporarily rolled the 405 migration back to `json`, inserted representative rows across every converted column category, verified `BackupItem::withAssignments()` works in the rollback-state schema, migrated forward to `jsonb`, and compared decoded payload semantics.
|
|
- The same down/up test asserted nullability, defaults, table index definitions, and table constraint definitions remain unchanged after conversion.
|
|
- The same test asserted there are no remaining public-schema columns with `data_type = 'json'`.
|
|
- Representative non-sensitive samples were written and read back through Eloquent casts and direct JSONB key predicates.
|
|
- Row/null counts were recorded before conversion from the local development database; converted tables are small enough for direct `ALTER COLUMN` locally. Staging/Dokploy must still validate real runtime and lock behavior.
|
|
|
|
Not performed in this session:
|
|
|
|
- Production-sized timing.
|
|
- Staging/Dokploy migration runtime.
|
|
- Full byte-level dump comparison. This is not required because `jsonb` canonicalizes textual representation; semantic preservation was tested instead.
|
|
|
|
## 10. Browser Proof
|
|
|
|
Focused browser proof passed using existing payload-backed smoke tests. No UI files were changed; this proof is regression-only.
|
|
|
|
Command:
|
|
|
|
```bash
|
|
cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec403EvidenceCurrentnessRuntimeClosureSmokeTest.php tests/Browser/Spec394ProviderFreshnessPermissionSmokeTest.php tests/Browser/Spec371BackupSetProductizationSmokeTest.php tests/Browser/Spec335RestoreRunDetailProductizationSmokeTest.php tests/Browser/Spec379ManagementReportPdfSmokeTest.php
|
|
```
|
|
|
|
Result:
|
|
|
|
```text
|
|
5 browser tests passed, 176 assertions, 19.87s
|
|
```
|
|
|
|
Covered surfaces:
|
|
|
|
- Evidence Overview and OperationRun proof currentness: `Spec403EvidenceCurrentnessRuntimeClosureSmokeTest.php`
|
|
- Provider freshness and required-permission readiness: `Spec394ProviderFreshnessPermissionSmokeTest.php`
|
|
- Backup set list/detail decision hierarchy and included backup items: `Spec371BackupSetProductizationSmokeTest.php`
|
|
- Restore run detail post-execution proof/results rendering: `Spec335RestoreRunDetailProductizationSmokeTest.php`
|
|
- Review Pack management PDF / Stored Report output state: `Spec379ManagementReportPdfSmokeTest.php`
|
|
|
|
Browser tests asserted no JavaScript errors and no unexpected console logs on the tested surfaces.
|
|
|
|
## 11. Regression Proof
|
|
|
|
Completed:
|
|
|
|
- PostgreSQL schema/type/index/model/query proof passed.
|
|
- PostgreSQL rollback/down-up preservation proof passed.
|
|
- Existing `BackupItem` unit regression suite passed.
|
|
- Focused browser proof passed across evidence, operations, provider, backup, restore, review pack, stored report, and management PDF surfaces.
|
|
- No UI/runtime surface files were edited.
|
|
- No authorization, global search, provider registration, destructive/high-impact action, or asset behavior was changed.
|
|
|
|
## 12. Staging Validation
|
|
|
|
Staging/Dokploy validation is not accessible from this agent session.
|
|
|
|
Required staging release checks before production:
|
|
|
|
- Run the migration on staging PostgreSQL.
|
|
- Confirm app boot.
|
|
- Run the focused PostgreSQL Spec405 test or equivalent staging validation.
|
|
- Smoke the representative payload-backed surfaces.
|
|
- Confirm no secrets or raw provider credential payloads appear in logs/screenshots.
|
|
|
|
Because staging is unavailable here, final readiness remains `PASS WITH CONDITIONS`.
|
|
|
|
## 13. Remaining Findings
|
|
|
|
- No P0 findings.
|
|
- No unresolved `json` column classification.
|
|
- No in-scope schema or application regression currently known after fixing rollback-compatible query handling and grouped table conversion.
|
|
- Remaining P1 condition: staging/Dokploy validation unavailable in this session.
|
|
- Browser proof passed locally.
|
|
|
|
## 14. Deferred Items
|
|
|
|
- Staging/Dokploy validation and migration runtime observation.
|
|
- Optional future online migration strategy if a production-sized table proves too large for direct `ALTER COLUMN`.
|
|
- Full browser/runtime audit remains out of scope.
|
|
- Governance artifact lifecycle and retention remain separate follow-up scope.
|
|
|
|
## 15. Validation Commands
|
|
|
|
Passed:
|
|
|
|
```bash
|
|
git diff --check
|
|
cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml tests/Feature/Database/JsonbDataLayerHardeningTest.php
|
|
cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Unit/BackupItemTest.php
|
|
cd apps/platform && ./vendor/bin/sail pint app/Models/BackupItem.php database/migrations/2026_06_23_000405_convert_trust_payload_json_columns_to_jsonb.php tests/Feature/Database/JsonbDataLayerHardeningTest.php
|
|
cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec403EvidenceCurrentnessRuntimeClosureSmokeTest.php tests/Browser/Spec394ProviderFreshnessPermissionSmokeTest.php tests/Browser/Spec371BackupSetProductizationSmokeTest.php tests/Browser/Spec335RestoreRunDetailProductizationSmokeTest.php tests/Browser/Spec379ManagementReportPdfSmokeTest.php
|
|
```
|
|
|
|
## 16. Product Surface, Filament, Deployment, and Recommended Next Step Close-Out
|
|
|
|
- **Application implementation status**: implemented locally with focused PostgreSQL rollback/down-up, unit, formatter, diff, and browser proof passing; staging validation still conditions the gate.
|
|
- **Livewire v4 compliance**: Livewire 4.1.4 confirmed by Laravel Boost; no Livewire code changed.
|
|
- **Provider registration location**: Laravel 12 panel providers remain in `apps/platform/bootstrap/providers.php`; no provider registration changed.
|
|
- **Global search posture**: unchanged. No globally searchable resource was added or modified.
|
|
- **Destructive/high-impact actions**: none added or changed; no confirmation/authorization behavior changed.
|
|
- **Asset strategy**: no frontend assets added, no `FilamentAsset` registration, no new `filament:assets` deploy requirement beyond the existing deployment baseline.
|
|
- **Product Surface Impact**: no runtime UI surface changed.
|
|
- **UI Surface Impact**: none; focused browser proof is regression-only.
|
|
- **No-legacy posture**: canonical data-layer conversion; no compatibility shim or dual-write path introduced.
|
|
- **Page archetype / surface budgets / Technical Annex / deep-link demotion / canonical status vocabulary**: N/A for changed code; existing surfaces remain unchanged.
|
|
- **Product Surface exceptions**: none.
|
|
- **Focused browser proof**: passed across evidence/currentness, operations, provider readiness, backup, restore, review pack, stored report, and management PDF surfaces.
|
|
- **Human Product Sanity**: visible complexity unchanged; no raw payload exposure added; current/released/failed/partial semantics unchanged.
|
|
- **Implementation-report fields**: Livewire v4, provider registration, global search, destructive/high-impact actions, asset strategy, deployment impact, tests/browser result, and visible complexity are recorded here.
|
|
- **Deployment impact**: database migration only. No env vars, queues, scheduler, storage, routes, provider scopes, panels, assets, or worker changes. Staging validation is required before production promotion.
|
|
- **No completed-spec rewrite assertion**: Specs 400-404 were read-only context; their files were not rewritten.
|
|
- **Recommended next step**: run staging PostgreSQL migration validation before production promotion.
|