# FieldOps Cloud Defect Register

Date: 2026-06-17

Severity definitions:

- SEV-1 Blocker: prevents install, core access, data safety, or commercial release.
- SEV-2 High: core workflow/security/business capability broken or incomplete.
- SEV-3 Medium: partial feature, validation, redirect, documentation, or non-critical workflow issue.
- SEV-4 Low: cosmetic or minor documentation issue.

| ID | Severity | Status | Area | Title | Evidence | Recommended fix | Retest |
| --- | --- | --- | --- | --- | --- | --- | --- |
| DEF-001 | SEV-1 | Fixed | Build | Fresh `composer install` failed | Yii package constraints referenced unavailable/abandoned versions and prevented lock generation | Removed abandoned/dev-only Yii web package, updated Yii component constraints to stable installable versions, and committed `composer.lock` | Passed `composer install --no-interaction --no-progress` |
| DEF-002 | SEV-1 | Fixed | Auth/Security | Demo auto-login was not production-gated | `public/index.php` previously logged in `demo@example.test` automatically without a production gate | Demo auto-login is now controlled through `AppEnvironment::shouldAutoLoginDemo()` and disabled when demo mode is disabled. | Passed `composer test`, `composer check`, XAMPP checks, and `tools/auth-production-smoke.cjs` |
| DEF-003 | SEV-2 | Fixed | Core CRUD | Client and job create flows did not persist created records | Older HTTP-only checks only saw validation/redirect behavior | DB-backed production workflow smoke now verifies client and job create/search/detail/edit persistence with demo disabled | Passed `tools/production-workflow-smoke.cjs` |
| DEF-004 | SEV-2 | Fixed for Gate 22 | API | API reference documented planned endpoints as if routed | `docs/API_REFERENCE.md` mixed active routes with future `/api/*` REST endpoints | Rewrote API reference, added `docs/API_CONTRACTS.md`, JSON `/api/*` 404/403 boundary errors, and `tools/api-contract-harness.php` to verify active route registration, planned REST route absence, disabled webhook JSON behavior, and docs truth markers | Passed `composer api-contract-harness` with 43 checks / 0 failures |
| DEF-019 | SEV-2 | Fixed for Gate 23 | Reports | Reports used hard-coded revenue and technician placeholder values | `/reports` rendered fixed revenue totals and `No assigned jobs yet` even when tenant/demo jobs had technicians | Added `ReportSummaryService`, wired `/reports` to tenant job/quote/invoice/team records, rendered explicit unassigned backlog, and added regression tests | Passed `composer test`, `composer check`, normal release gate, MySQL smokes, and MySQL-enabled release gate |
| DEF-020 | SEV-2 | Fixed for Gate 24 | Dashboard | Dashboard used static KPI values and a fake revenue trend | `/dashboard` read `OperationsDemoData::dashboardStats()`, rendered a fixed `+12% from last month`, and showed approved quotes inside Pending Quotes | Added `DashboardSummaryService`, wired `/dashboard` to tenant job/quote/invoice records, removed the fake trend, filtered pending quotes to draft/sent, and added regression tests | Passed `composer test`, `composer check`, normal release gate, MySQL smokes, MySQL-enabled release gate, XAMPP release gates, browser smoke, role interaction smoke, and accessibility smoke |
| DEF-021 | SEV-2 | Fixed for Gate 25 | Reports/Dashboard | Date-scoped summaries were not explicit | Reports and dashboard values could be shown as current-period-style metrics without a shared period selector/filtering contract | Added `ReportPeriodService`, `/reports` and `/dashboard` period selectors, custom date filtering, and custom-period regression tests | Passed `composer test`, `composer check`, `composer validate --no-check-publish`, `composer audit --locked`, `composer release-gate`, `composer mysql-isolation-smoke`, `composer mysql-volume-profile`, MySQL-enabled `composer release-gate`, XAMPP `composer check`, XAMPP release gates, browser smoke, role interaction smoke, and accessibility smoke; full Gate 25 release checks recorded in `docs/MASTER_PUBLIC_RELEASE_GATE25_PERIOD_SCOPED_SUMMARIES.md` |
| DEF-022 | SEV-2 | Fixed for Gate 26 | Reports/Dashboard | Previous-period trends were missing after fake trend removal | Gate 24 correctly removed static trend copy and Gate 25 added period filters, but Dashboard/Reports still lacked calculated previous-period comparisons | Added `ReportPeriodService::previous()`, dashboard trend notes, report comparison rows, and February-vs-prior-period regression tests | Passed `composer test`, `composer check`, `composer validate --no-check-publish`, `composer audit --locked`, `composer release-gate`, `composer mysql-isolation-smoke`, `composer mysql-volume-profile`, MySQL-enabled `composer release-gate`, XAMPP `composer check`, XAMPP release gates, browser smoke, role interaction smoke, and accessibility smoke; full Gate 26 release checks recorded in `docs/MASTER_PUBLIC_RELEASE_GATE26_PREVIOUS_PERIOD_TRENDS.md` |
| DEF-023 | SEV-2 | Fixed for Gate 27 | Reports | Advanced report summaries were missing | Reports had core summaries, period filters, and previous-period comparisons, but no computed productivity, conversion, engineer, customer, or profitability-readiness summaries | Extended `ReportSummaryService`, wired advanced report cards into `/reports`, and added service/render regression tests | Passed syntax checks, `composer test`, `composer check`, `composer validate --no-check-publish`, `composer audit --locked`, release gates, MySQL isolation/volume checks, XAMPP served-copy release gates, browser smoke, role interaction smoke, and accessibility smoke. |
| DEF-024 | SEV-2 | Fixed for Gate 28 | Reports | Saved report presets were schema-only | `saved_reports` existed in the schema, but there was no runtime repository, service, route, UI, or tenant-scoped persistence for report presets | Added saved report repositories, validation service, `/reports` save/open/delete UI, POST routes, tenant-scoped DB/session persistence, and audit events | Passed syntax checks, `composer test`, `composer check`, `composer validate --no-check-publish`, `composer audit --locked`, release gates, MySQL isolation/volume checks, XAMPP served-copy release gates, browser smoke, role interaction smoke, and accessibility smoke. |
| DEF-025 | SEV-2 | Fixed for Gate 29 | Reports | Scheduled report delivery had no durable local foundation | Saved report presets could store cadence metadata, but there was no tenant-scoped delivery job record, queue action, provider-missing status, or audit event for scheduled delivery readiness | Added `report_delivery_jobs`, demo/database delivery repositories, `ReportDeliveryService`, `/reports` delivery queue UI, queue route, `manage_reports` RBAC, and audit event coverage | Passed syntax checks, `composer test`, `composer check`, `composer validate --no-check-publish`, `composer audit --locked`, release gates, MySQL isolation/volume checks, XAMPP served-copy release gates, browser smoke, role interaction smoke, and accessibility smoke. |
| DEF-026 | SEV-2 | Fixed for Gate 30 | Reports | Profitability had no cost-backed local foundation | Gate 27 correctly withheld margin claims when no cost data existed, but Reports did not yet compute margin from real tenant job cost capture | Added `ReportProfitabilityService`, wired `/reports` to tenant inventory movements, rendered costed invoice/material-cost/margin rows, linked demo invoice to existing job material movement, and added `idx_inventory_movements_tenant_job_created` | Passed syntax checks, `composer test`, `composer check`, `composer validate --no-check-publish`, `composer audit --locked`, release gates, MySQL isolation/volume checks, XAMPP served-copy release gates, browser smoke, role interaction smoke, and accessibility smoke. |
| DEF-027 | SEV-2 | Fixed for Gate 31 | Jobs/Reports | Direct labour and subcontractor costs were not captured locally | Gate 30 added material-cost-backed profitability, but jobs still lacked a durable direct cost ledger for labour, subcontractor, equipment, travel, disposal, or other manual costs | Added `job_cost_entries`, job cost repositories, `JobCostService`, `POST /jobs/costs`, `manage_job_costs` RBAC, job detail cost ledger, audit event `job_cost_recorded`, demo seeds/reset, and report profitability rollups for direct job costs | Passed syntax checks, `composer test`, `composer check`, `composer validate --no-check-publish`, `composer audit --locked`, release gates, MySQL isolation/volume checks, XAMPP served-copy release gates, browser smoke, role walkthrough, role interaction smoke, and accessibility smoke. |
| DEF-028 | SEV-2 | Fixed for Gate 32 | Reports | Contract-level profitability was missing | Gates 30-31 added material and direct job cost capture, but Reports did not roll up profitability by maintenance agreement or contract | Added `ReportContractProfitabilityService`, wired maintenance agreements and billing schedules into `/reports`, rendered Contract Profitability, linked demo agreement/job/invoice/cost scenarios, and added regression tests that exclude unlinked same-customer invoices | Passed syntax checks, `composer test`, and `composer check`; full Gate 32 release checks recorded in `docs/MASTER_PUBLIC_RELEASE_GATE32_CONTRACT_PROFITABILITY_FOUNDATION.md` |
| DEF-029 | SEV-2 | Fixed for Gate 33 | Reports/Purchasing | Purchase-order accrual was missing from profitability | Gates 30-32 added material, direct, and contract profitability, but committed purchase orders were still excluded from local cost rollups | Added tenant-scoped purchase-order schema, demo/database repositories, `PurchaseOrderAccrualService`, report wiring, `/reports` Purchase-order accrual rendering, demo seeds/reset, and regression tests for draft/cancelled exclusion plus cross-tenant line isolation | Passed syntax checks, `composer test`, `composer check`, `composer validate --no-check-publish`, and `composer audit --locked`; full Gate 33 release checks recorded in `docs/MASTER_PUBLIC_RELEASE_GATE33_PURCHASE_ORDER_ACCRUAL_FOUNDATION.md` |
| DEF-030 | SEV-2 | Fixed for Gate 34 | Reports/Purchasing | Supplier invoice matching was missing from profitability | Gate 33 added purchase-order accruals, but actual supplier invoices were still absent and matched PO commitments could not be replaced by actual supplier cost | Added tenant-scoped supplier invoice schema, demo/database repositories, `SupplierInvoiceMatchingService`, report wiring, `/reports` supplier invoice cost rendering, demo matching/exclusion scenarios, and regression tests for draft exclusion, matched PO replacement, and cross-tenant line isolation | Passed `composer test`, `composer check`, MySQL-enabled `composer release-gate`, XAMPP served-copy checks, browser smoke, role walkthrough, role interaction smoke, and accessibility smoke; full Gate 34 release checks recorded in `docs/MASTER_PUBLIC_RELEASE_GATE34_SUPPLIER_INVOICE_MATCHING_FOUNDATION.md` |
| DEF-031 | SEV-2 | Fixed for Gate 35 | Reports/Import | Payroll and time-sheet labour import was missing from profitability | Gate 34 added supplier invoice matching, but approved labour from payroll/time-sheet sources still could not be imported, validated, undone, tenant-scoped, or included as a separate labour-cost bucket | Added tenant-scoped `timesheet_entries`, demo/database repositories, `TimesheetCostService`, Timesheets / payroll import schema and validation, import commit/undo wiring, report profitability rollups, `/reports` Timesheet labour cost rendering, demo seed/reset scenarios, and regression tests for draft exclusion, approved labour rollups, schema indexes, and cross-tenant isolation | Passed `composer test`, `composer check`, `composer validate --no-check-publish`, `composer audit --locked`, MySQL-enabled `composer release-gate`, MySQL isolation/volume smokes, XAMPP served-copy checks, browser smoke, role walkthrough, role interaction smoke, and accessibility smoke; full Gate 35 release checks recorded in `docs/MASTER_PUBLIC_RELEASE_GATE35_PAYROLL_TIMESHEET_IMPORT_FOUNDATION.md` |
| DEF-032 | SEV-2 | Fixed for Gate 36 | Customer portal/Production smoke | Production workflow smoke did not cover portal placeholder flows and XAMPP portal forms could double-prefix the base path | The local production smoke covered owner CRUD and route matrices, but customer portal quote approval, invoice payment validation/recording, booking requests, and XAMPP portal form actions were not proven end-to-end | Extended `tools/production-workflow-smoke.cjs`, added `composer production-workflow-smoke`, wired optional release-gate coverage, normalized duplicated XAMPP base paths, fixed portal form action rendering when `APP_BASE_URL` is active, and extended XAMPP role interaction smoke with portal quote/payment checks | Passed syntax checks, `composer test`, `composer check`, production workflow smoke with `failureCount=0`, XAMPP served-copy checks, and XAMPP role interaction smoke with `failureCount=0`; full Gate 36 release checks recorded in `docs/MASTER_PUBLIC_RELEASE_GATE36_PRODUCTION_WORKFLOW_SMOKE.md` |
| DEF-005 | SEV-2 | Fixed | Security | Production session/header hardening incomplete | Response cookie lacked HttpOnly/SameSite, CSP was absent, and `X-Powered-By` was exposed | Added session strict-mode/cookie policy, CSP, Permissions-Policy, production HTTPS HSTS, and `X-Powered-By` removal | Passed `composer test` and `tools/auth-production-smoke.cjs` header/cookie checks |
| DEF-006 | SEV-2 | Open | Integrations | Live accounting/calendar/LLM integrations are foundations only | Settings/provider registries exist; no OAuth callbacks, webhooks, live sync workers, or external LLM calls are enabled | Gate 6: keep UI labelled as sandbox/foundation until mocked provider contracts and live credential flows are implemented | Retested by code/docs inspection 2026-06-16 |
| DEF-007 | SEV-2 | Fixed for Gate 5 | Billing/SaaS | Billing provider truth and webhook processing were incomplete | Pricing/subscription foundations existed but runtime state implied Stripe readiness while no signed webhook/idempotency path existed | Added manual-billing default, provider readiness gating, database-backed billing override/event repository, signed Stripe webhook verification, replay tolerance, tenant metadata requirement, provider-event idempotency, UI truth labels, and tests. Live payment collection remains blocked until provider credentials and price ids are configured. | Passed `composer test`, `composer check`, and `tools/production-workflow-smoke.cjs` with `failureCount=0` |
| DEF-008 | SEV-2 | Fixed | Import | CSV import production upload hardening was incomplete | Import now supports selected data type, CSV file/paste preview, mandatory field validation, upload extension/MIME/size checks, binary/UTF-8/header/row/formula validation, commit, duplicate-commit blocking, rollback of earlier created records on failed imports, undo, durable validation reports, durable import job lifecycle, durable export jobs, bounded retry-state transitions, bounded payload replay queue/claim/complete/failure state, browser multipart upload smoke coverage, Gate 9 500-row local performance smoke, Gate 18 import/export history persistence, Gate 19 retry-state coverage, and Gate 21 payload replay foundation coverage | Keep hosted worker runner evidence and hosted-scale load proof as later release hardening, but Gate 4 upload hardening, Gate 9 local large-data smoke, Gate 18 durable import/export history, Gate 19 retry-state foundation, and Gate 21 payload replay foundation are closed locally | Passed `composer test`, `composer check`, `tools/production-workflow-smoke.cjs` with multipart upload checks, `tools/performance-smoke.php`, XAMPP `tools/browser-smoke.cjs`, and XAMPP `tools/role-walkthrough.cjs` |
| DEF-017 | SEV-2 | Fixed for Gate 10 | Mobile | Mobile/app-store readiness was not machine-verifiable | PWA/offline/Capacitor files existed, but the platform did not have a release-gate service/report distinguishing local mobile readiness from signed app-store readiness | Added `MobileAppReadinessService`, `tools/mobile-readiness.php`, platform-admin mobile release-gate visibility, mobile evidence env vars, and app-store readiness docs. Signed native submission remains blocked until owner evidence exists | Passed `php tools\mobile-readiness.php` and `php tests\run.php` |
| DEF-018 | SEV-2 | Fixed for Gate 11 | CI/Release | No committed CI release gate existed | Release checks were documented but not represented by a committed workflow/runner | Added `tools/release-gate.php`, Composer `release-gate`, `.github/workflows/fieldops-release-gate.yml`, and generated release-gate report. Real hosted CI run evidence remains required | Passed `composer release-gate` and `php tests\run.php` |
| DEF-016 | SEV-2 | Fixed for Gate 12 | Tenant isolation | MySQL-backed tenant isolation lacked broad repository proof | Prior checks were mainly SQLite workflow negatives and code inspection | Added `TenantReferenceGuard`, guarded high-risk cross-tenant relationships, fixed quote/invoice child-row delete ordering, restored `tools/mysql-isolation-smoke.php`, and wired the smoke into Composer/release-gate/CI | Passed `composer mysql-isolation-smoke` with 16 checks, `composer release-gate`, `composer test`, `composer check`, and `tools/production-workflow-smoke.cjs` |
| DEF-009 | SEV-3 | Fixed | Routing | `/export-data` produced PHP fatal | Route called `exportData()` without required `Request` | Passed `Request` to route handler | Passed route smoke |
| DEF-010 | SEV-3 | Fixed | XAMPP redirects | Client/job successful POSTs redirected to `/clients` or `/jobs` outside base path | Final URL became `http://localhost/jobs` before fix | Added base-path redirect helpers | Passed form-flow smoke |
| DEF-011 | SEV-3 | Fixed | CSV export security | CSV exports did not escape formula-leading cells | Static inspection found direct `fputcsv` of raw cells | Added CSV cell formula escaping | Verified `=1+1` exports as `'=1+1` |
| DEF-012 | SEV-3 | Fixed | Docs | Testing template expected `docs/SECURITY_NOTES.md`, but file was at repo root | File inspection | Added canonical `docs/SECURITY_NOTES.md` and kept root note as a pointer | File inspection |
| DEF-013 | SEV-3 | Fixed | Dependency audit | `composer audit` could not run | No installable dependency set and no lock file | Resolve DEF-001, then run `composer audit` | Passed; no known vulnerability advisories found |
| DEF-014 | SEV-3 | Open | Browser tooling | Browser smoke requires system Chrome and pnpm module path | Bundled Playwright package lacked normal top-level resolution | Document command or add project-managed browser test dependency after owner approval | Partially mitigated by `tools/browser-smoke.cjs` |
| DEF-015 | SEV-2 | Fixed | Auth/RBAC | Read-only demo user could promote to platform admin by opening `/platform-admin` | Demo-mode `/platform-admin` route silently replaced a `demo_user` session with a `platform_admin` session | Removed implicit promotion; platform admin demo entry is explicit through `/demo/platform-admin` or `/demo/role?role=platform_admin`; added regression coverage and role walkthrough | Passed `composer test`, `composer check`, `tools/role-walkthrough.cjs`, and in-app browser spot check |

## Fixed Files

- `public/index.php`
- `src/Application/App.php`
- `src/Client/Controller/ClientController.php`
- `src/Job/Controller/JobController.php`
- `src/Demo/Controller/OperationsController.php`
- `src/Reports/Service/ReportSummaryService.php`
- `src/Dashboard/Controller/DashboardController.php`
- `src/Dashboard/Service/DashboardSummaryService.php`
- `src/Reports/Service/ReportPeriodService.php`
- `docs/MASTER_PUBLIC_RELEASE_GATE27_ADVANCED_REPORT_SUMMARIES.md`
- `src/Importing/Service/CsvUploadValidator.php`
- `src/Importing/Service/ImportPipelineService.php`
- `src/Importing/Service/ImportValidationService.php`
- `src/Importing/Repository/ImportExportJobRepository.php`
- `tools/browser-smoke.cjs`
- `tools/role-walkthrough.cjs`
- `tools/role-interaction-smoke.cjs`
- `tools/auth-production-smoke.cjs`
- `tools/production-workflow-smoke.cjs`
- `tools/mysql-isolation-smoke.php`
- `tools/api-contract-harness.php`
- `composer.json`
- `composer.lock`
- `src/Demo/Service/DemoRoleIdentityService.php`
- `src/Dispatch/Controller/DispatchController.php`
- `src/Infrastructure/Security/RbacService.php`
- `src/Infrastructure/Security/SecurityHeaderService.php`
- `src/Infrastructure/Security/SessionCookiePolicy.php`
- `src/Saas/Service/SecurityAdminService.php`
- `src/Saas/Service/BillingProviderStatusService.php`
- `src/Saas/Service/BillingWebhookService.php`
- `src/Saas/Repository/PlatformBillingRepository.php`
- `src/Saas/Repository/DatabasePlatformBillingRepository.php`
- `src/Saas/Repository/DemoPlatformBillingRepository.php`
- `src/Saas/Controller/BillingWebhookController.php`
- `templates/layouts/main.php`
- `templates/dashboard/index.php`
- `templates/reports/index.php`
- `templates/saas/platform-admin.php`
- `templates/site/demo.php`
- `tests/run.php`

## Open Release Blockers

Commercial deployment is no longer blocked by DEF-003, DEF-004, DEF-007, DEF-008, DEF-016, DEF-017, DEF-018, DEF-019, DEF-020, DEF-021, DEF-022, DEF-023, DEF-024, DEF-025, DEF-026, DEF-027, DEF-028, DEF-029, DEF-030, DEF-031, DEF-032, production role walkthrough coverage, Gate 3 MySQL tenant-isolation proof, Gate 4 import upload hardening, Gate 7 app-level deployment hardening, Gate 8 accessibility smoke, Gate 9 local performance smoke, Gate 10 local mobile readiness, Gate 11 release-gate automation, Gate 12 MySQL smoke restore, Gate 17 local MySQL volume profiling, Gate 18 durable import/export persistence, Gate 19 import retry-state foundation, Gate 20 selected role interaction smoke, Gate 21 import payload replay foundation, Gate 22 API contract truth, Gate 23 reports durability, Gate 24 dashboard durability, Gate 25 period-scoped summaries, Gate 26 previous-period trends, Gate 27 advanced report summaries, Gate 28 saved report presets, Gate 29 scheduled report delivery foundation, Gate 30 material-cost-backed profitability foundation, Gate 31 direct job cost capture foundation, Gate 32 contract profitability foundation, Gate 33 purchase-order accrual foundation, Gate 34 supplier-invoice matching foundation, Gate 35 payroll/time-sheet import foundation, or Gate 36 production workflow browser smoke. It remains blocked by DEF-006 plus the master release gates for live report provider delivery and hosted worker evidence, public REST implementation if launch-scoped, live provider activation, live payment activation, owner-provided hosted deployment evidence, signed native app-store submission, real hosted CI/deployment evidence, hosted-scale load proof, live payroll/provider sync, and live accounting-provider cost import.
