OViq Hotel ERP — Phase 6 executed verification record Date: 2026-10-20 Environment: PHP 8.3.6, MySQL 8.0.46, Node.js, headless Chromium. PHP target >=8.2. No claim is made that PHP8.2, Safari, Firefox, Windows, production PHP-FPM/Nginx, actual OTA APIs or payment gateways were tested. 119 prior-phase regression assertions 60 Phase 6 service assertions (includes independent PHP/MySQL process races) 31 HTTP installation, route and migration checks 16 HTTP isolation, account revocation, 2FA fail-closed and throttle checks 23 real-browser workflow, responsive navigation and offline checks 10 actual archived Phase5 upgrade and backup/restore checks Total: 259 reported assertions/checks across these layers (not 259 unique features). Additional checks: PHP syntax lint for every shipped PHP file, Node.js syntax validation for local JavaScript, fresh schema/seed import and ZIP integrity. The optional GitHub workflow was supplied as code, not activated or executed. Targeted race coverage: - two independent workers contend for the same room/stay; exactly one booking - two identical POS payment submissions; exactly one receipt persisted - two workers close one business date; exactly one close and room-night charge These are correctness races, NOT a sustained load or high-availability test. Audit-trigger tests use a DBA-installed trigger fixture. Web installer deliberately requires no SUPER privilege; operators must separately install audit guards and run preflight before any live cutover. Read deployment notes and release status. Preflight intentionally returns failure for missing guards and ownerless legacy inventory. Those failing gates were tested as expected blockers, not ignored. Browser workflow: local Bootstrap, room/type setup, guest registration, walk-in, receipt and checkout, tape chart, CRM drag/drop and accessible movement, mobile sidebar, static-only offline fallback and no uncaught JavaScript errors. A browser screenshot in tests/previews is test-fixture data, not a live property. Restore drill: CLI backup with a dedicated DBA fixture, SHA-256 reporting, no-overwrite guard, restore into a separate database, table/record count and audit trigger checks. Does not certify your production backup infrastructure. Remaining functional and infrastructure gates are in RELEASE-STATUS.txt and DEPLOYMENT.txt. A successful test run is not a production security certification. ==== Prior-phase regression assertions ==== PASS Authenticated property context resolves assigned property PASS Super-admin permission gate succeeds PASS Housekeeper denied CRM permission PASS Forged CSRF token rejected PASS Issued CSRF token accepted PASS Lead created at version zero PASS Lead stage persists PASS Stale lead update rejected PASS Unknown pipeline stage rejected PASS Cross-property lead update denied PASS Invalid calendar date rejected PASS Blank lead title rejected PASS Work assigned to technician PASS Asset retirement blocked while work outstanding PASS Work lifecycle reaches closed PASS Closed work cannot advance PASS Due maintenance produces one work order PASS Repeated due generation creates no duplicate PASS Retired assets cannot reactivate PASS Event quote equals two hours times hall rate PASS Overlapping event rejected PASS Back-to-back hall booking accepted PASS Hall capacity enforced PASS Completed event cannot reopen PASS Event cancellation persists PASS Cross-property hall booking denied PASS Pricing defaults disabled PASS Disabled pricing engine rejects generation PASS Pricing toggle persists PASS Pricing generates two daily recommendations PASS Regeneration uses unique date/type records PASS No duplicate recommendations PASS Approved recommendation stored as date override PASS Reapplying recommendation rejected PASS Base room-type rate unchanged PASS High-occupancy pricing formula verified PASS Low-occupancy pricing formula verified PASS Audit and mutation transaction rolls back together PASS Workflow audit records written PASS Controller renders crm PASS Controller renders maintenance PASS Controller renders events PASS Controller renders pricing PASS Controller renders reports PASS Date-rate API rejects missing inputs PASS Date-rate API returns approved override PASS Route handler exists /login PASS Route handler exists / PASS Route handler exists /dashboard PASS Route handler exists /pms/calendar PASS Route handler exists /pms/calendar-data PASS Route handler exists /pms/available-rooms PASS Route handler exists /pms/reservations PASS Route handler exists /pms/reservations/create PASS Route handler exists /pms/reservations/{id} PASS Route handler exists /pms/rooms PASS Route handler exists /pms/guests PASS Route handler exists /pms/guests/{id} PASS Route handler exists /pms/night-audit PASS Route handler exists /front-office PASS Route handler exists /pos PASS Route handler exists /pos/orders/{id} PASS Route handler exists /pos/kitchen PASS Route handler exists /housekeeping PASS Route handler exists /inventory PASS Route handler exists /inventory/purchase-orders PASS Route handler exists /inventory/purchase-orders/{id} PASS Route handler exists /accounting PASS Route handler exists /crm PASS Route handler exists /maintenance PASS Route handler exists /events PASS Route handler exists /pricing PASS Route handler exists /reports PASS Route handler exists /reports/export PASS Route handler exists /pms/date-rate PASS Route handler exists /login PASS Route handler exists /logout PASS Route handler exists /pms/reservations PASS Route handler exists /pms/reservations/{id}/checkin PASS Route handler exists /pms/reservations/{id}/checkout PASS Route handler exists /pms/reservations/{id}/transition/{action} PASS Route handler exists /pms/reservations/{id}/charges PASS Route handler exists /pms/reservations/{id}/payments PASS Route handler exists /pms/room-types PASS Route handler exists /pms/rooms PASS Route handler exists /pms/rooms/{id}/status PASS Route handler exists /pms/guests PASS Route handler exists /pms/guests/{id} PASS Route handler exists /pms/night-audit/run PASS Route handler exists /front-office/wakeup PASS Route handler exists /front-office/wakeup/{id}/complete PASS Route handler exists /pos/outlets PASS Route handler exists /pos/tables PASS Route handler exists /pos/categories PASS Route handler exists /pos/items PASS Route handler exists /pos/orders PASS Route handler exists /pos/orders/{id}/items PASS Route handler exists /pos/orders/{id}/items/{item_id}/void PASS Route handler exists /pos/orders/{id}/items/{item_id}/split PASS Route handler exists /pos/orders/{id}/send-kitchen PASS Route handler exists /pos/orders/{id}/pay PASS Route handler exists /pos/orders/{id}/room-charge PASS Route handler exists /pos/kitchen/{item_id}/advance PASS Route handler exists /housekeeping/tasks PASS Route handler exists /housekeeping/tasks/{id}/assign PASS Route handler exists /housekeeping/tasks/{id}/advance PASS Route handler exists /housekeeping/laundry PASS Route handler exists /housekeeping/laundry/{id}/move PASS Route handler exists /housekeeping/lost-found PASS Route handler exists /housekeeping/lost-found/{id}/claim PASS Route handler exists /inventory/items PASS Route handler exists /inventory/stores PASS Route handler exists /inventory/adjust PASS Route handler exists /inventory/purchase-orders PASS Route handler exists /inventory/purchase-orders/{id}/approve PASS Route handler exists /inventory/purchase-orders/{id}/receive PASS Route handler exists /accounting/journal PASS Route handler exists /accounting/expenses PASS Route handler exists /ops/{module}/{action} TOTAL 119 assertions passed; 73 registered routes. ==== Phase 6 service and independent-process race assertions ==== PASS Property context established PASS Decimal money addition uses exact minor units PASS Fractional line rounds half up PASS Negative monetary input rejected PASS Excess decimal places rejected PASS Cross-property guest rejected by reservation service PASS Room maximum occupancy enforced PASS Concurrent same-room booking: exactly one writer succeeds PASS Concurrent booking creates only one reservation PASS Unassigned reservations cannot oversell room-type inventory PASS Dirty/cleaning room cannot be checked in PASS Unpaid folio cannot check out PASS Folio includes room tax and extra charges exactly once PASS Identical folio payment replay is idempotent PASS Payment key reuse with changed amount rejected PASS Folio overpayment rejected PASS Paid checkout sends room to cleaning PASS Checkout generates one cleaning task PASS Closed folio rejects charges PASS Occupied restaurant table cannot be reopened PASS Split tax totals use exact minor units PASS POS partial-payment replay creates no duplicate PASS Split payment cannot exceed remaining balance PASS Cannot redistribute partially-paid lines PASS Fully-paid split rejects additional payment PASS All splits settled marks order paid PASS Settled order frees table PASS Settled order cannot be voided PASS Concurrent identical payment requests both resolve successfully PASS Concurrent payment replay persists only one receipt PASS Still-open current business date cannot be closed PASS Concurrent night audit closes date once PASS Night audit posts exactly one room charge per business date PASS Night audit does not double count quoted room amount PASS Opening stock adjustment persists PASS Negative inventory stock rejected PASS Cross-property stock adjustment rejected PASS Partial GRN advances PO state PASS Cumulative GRN over-receipt rejected PASS Weighted-average cost includes stock in both stores PASS Receipt leaves other store quantity unchanged PASS Receiving store gets exact received quantity PASS Fully-received PO closes PASS Double-entry journal balances exactly PASS Journal uses property currency, not hardcoded USD PASS Unbalanced journal rejected PASS Expense cannot post to an asset account PASS Rejected expense leaves no partial record PASS Expense journal preserves expense date PASS Database rejects audit update PASS Database rejects audit deletion PASS Login attempt bucket updated 1 PASS Login attempt bucket updated 2 PASS Login attempt bucket updated 3 PASS Login attempt bucket updated 4 PASS Login attempt bucket updated 5 PASS New session does not bypass database login throttle PASS Native DI resolves typed dependencies PASS Named routes encode path parameters PASS Dynamic SQL identifiers validated TOTAL 60 Phase 6 hardening assertions passed. ==== HTTP installer and route regression ==== PASS Uninstalled application routes to public installer PASS Installer rejects missing CSRF PASS Installer database configuration succeeds PASS Installer builds all tables and seeds identity catalog PASS Installer creates administrator and completes lock step PASS Installation lock written PASS Installed wizard cannot be reopened PASS Login rejects missing CSRF PASS Login authenticates and dashboard renders PASS Authenticated route /crm renders PASS Authenticated route /maintenance renders PASS Authenticated route /events renders PASS Authenticated route /pricing renders PASS Authenticated route /reports renders PASS Authenticated route /pms/calendar renders PASS Authenticated route /pms/rooms renders PASS Authenticated route /pos renders PASS Authenticated route /accounting renders PASS Nested-page base URL anchored at application root PASS CRM mutation rejects missing CSRF PASS Lead creation escapes stored HTML when rendered PASS AJAX lead movement persists PASS AJAX stale version returns conflict PASS Invalid report date returns 422 PASS Report CSV export responds PASS Unregistered route returns 404 without fatal error PASS Service worker excludes authenticated page persistence PASS CLI migration runner handles fresh install and rerun PASS Phase 4-style database receives Phase 5 additions PASS Non-CRM role denied CRM page PASS Housekeeper denied pricing page TOTAL 31 HTTP/deployment checks passed. ==== Cross-property/session/throttle HTTP checks ==== PASS Foreign guest detail denied PASS Foreign reservation detail denied PASS Foreign POS order detail denied PASS Foreign outlet detail denied PASS Property-isolated collection /pms/guests PASS Property-isolated collection /pms/reservations PASS Property-isolated collection /pms/reservations/create PASS Property-isolated collection /inventory PASS Property-isolated collection /front-office PASS Property-isolated collection /dashboard PASS Cross-property checkout denied before mutation PASS Foreign inventory input cannot cross resource boundary PASS Unsupported JSON mutation fails closed PASS Disabled account loses existing session access PASS 2FA-marked account cannot silently bypass unsupported second factor PASS HTTP login throttle survives six fresh cookie jars TOTAL 16 security HTTP checks passed. ==== Chromium end-to-end and offline checks ==== PASS Desktop sidebar renders PASS Room type setup submits successfully PASS Room setup creates clean room tile PASS Guest registration reaches profile PASS Walk-in guest checked in through real browser form PASS Folio receipt records through idempotent payment form PASS Paid browser checkout succeeds PASS Tape chart JavaScript renders fourteen-day grid PASS Drag-and-drop CRM movement persists after reload PASS Accessible CRM selector persists stage change PASS Browser route renders /maintenance PASS Browser route renders /events PASS Browser route renders /pricing PASS Browser route renders /reports PASS Browser route renders /accounting PASS Browser route renders /housekeeping PASS Browser route renders /pos PASS Mobile sidebar toggle works at 390px PASS Mobile dashboard avoids document-level horizontal overflow PASS Browser cache contains no authenticated HTML pages PASS Offline navigation displays static fallback, not guest data PASS No uncaught browser JavaScript errors PASS No external asset requests needed for application rendering TOTAL 23 browser checks passed. ==== Real archived upgrade and backup restore checks ==== PASS Archived Phase5 database upgrades through Phase6 PASS Actual upgrade migration rerun is idempotent PASS Unknown legacy inventory ownership is preserved for manual reconciliation PASS Preflight blocks unresolved legacy inventory PASS Preflight reports missing DBA audit guards PASS DBA audit-guard installer succeeds and can be rerun PASS CLI backup produces a checksum-verified SQL dump PASS Backup tool refuses to overwrite an existing file PASS Backup restores matching table and fixture record counts into another database PASS Restore includes both append-only audit triggers TOTAL 10 upgrade/backup checks passed.