OViq Hotel ERP — Phase 10: localization foundation and translation administration
Executed verification date: 2026-10-24
Runtime: PHP 8.3.6, MySQL 8.0.46, Node.js 22.23.3 and headless Chromium.
120 PHP files passed syntax checks; all public JavaScript passed node --check.
PHP >=8.2 is the source target. PHP8.2/non-Chromium browsers were not locally run. CI matrix is supplied as code, not activated or remotely executed.

TOTAL: 1002 automated assertions/checks across layers below. This includes 300 per-language message UTF-8/placeholder validations (75 keys x 4 languages), not 1002 unique modules/features. Passing tests does not certify production security or language quality.

IMPLEMENTED
- 75 registered message keys per language: English, French, Kiswahili and Arabic.
- Guest/authenticated language selector; saved signed-in preference reuses existing users.locale; sign-in loads saved preference; property switch retains chosen session language.
- Translated sidebar, theme labels, sign-in/challenge labels, dashboard and translation administration. HTML lang/dir and Content-Language metadata; Arabic RTL shell/mobile opening and closing.
- Active-property override editor, settings.manage gate, current password/fresh enrolled-factor confirmation, search and 20-key pagination; active-override JSON export.
- Registered key/locale whitelist, valid UTF-8/control-character/length validation, exact placeholder multiplicity, escaped text and dynamic values, safe return-route allowlist.
- Optimistic versions; inactive tombstones prevent stale overwrite after delete/recreate; actor/payload-bound request keys; audit-atomic changes; same-key retry and concurrent editor protection.
- Legacy unscoped translations and saved unsupported locales preserved; unscoped rows do not become global runtime overrides. Unsupported user locale falls back to English.
- French dashboard revenue display only uses a decimal comma/narrow-space grouping. Canonical transaction/API/input/CSV/DB decimals, dates, currency and authorization are unchanged.
- PWA static cache version is phase10; authenticated/translation pages and responses remain network-only/no-store.

NEW TEST COVERAGE
The localization suite validates complete key coverage in four dictionaries and all 300 supplied message values/placeholders; rejects traversal, unknown keys/languages, malformed UTF-8, controls, oversized/empty text and missing/repeated/unexpected placeholders; proves tenant isolation, preference persistence, guest/public separation, HTML escaping, dynamic name escaping, saved-language sign-in, legacy-global inactivity, and audit-failure rollback of override/request data.
The independent-process suite checks simultaneous same-key save returns, one-row/version persistence, different edits of one version (one winner), removal-versus-edit ordering, monotonic tombstones and revoked-session rejection. These are targeted correctness races, not a load/HA/pentest test.
Browser acceptance checks French guest credentials labels, saved preference after logout/sign-in, Kiswahili dashboard, Arabic RTL sidebar on desktop and mobile (including reachable close toggle), localized editor, password confirmation, retry idempotency, literal-markup output, placeholder rejection, scoped JSON export, branch isolation with retained user language, removal fallback, CSRF, redirect/path validation, denied staff administration/export/POST, permitted staff preference changes and no uncaught JS errors/private cache entries.
Existing browser sign-in locators were narrowed to the actual sign-in form because the page now also has a language form. Earlier authentication/business assertions were retained and rerun.
Actual archived Phase9 schema migrates non-destructively, reruns safely, preserves registered/unsupported saved locales, home/role/password/session state, memberships and global translation records, and creates no automatic scoped overrides. Older archived migration/backup/restore/operator suites also passed.

SCOPE / ACCEPTANCE LIMITS
This is NOT full ERP localization. Most PMS/POS, HR/payroll, inventory, CRM, maintenance/events, property/security administration, errors, CSV/CLI/offline and legal-document text still uses English. Role/property/user names and historical payroll snapshots are not translated. Initial dictionary text requires qualified native-speaking operational review; no professional linguistic/legal certification or external machine translation service is claimed.
No pluralization, regional locale negotiation, date/calendar conversion, translated number input, Arabic-Indic digit conversion, FX, locale-specific statutory rules, bulk import or arbitrary new keys is supplied. Public login has no tenant identity and ignores property override data (including scoped auth.* text); it uses built-in catalogues only. Guest choice is session-only and clears at logout. Each live user session keeps its own language until changed/new sign-in reloads the account preference.
No real provider APIs, gateways, monetary transfers, production data, production infrastructure, pentest or high-load test was used. Test screenshots contain synthetic data only. Test-only audit failure injection uses isolated DBA privileges; application does not require SUPER.

DEPLOYMENT
Back up/restore-drill first; preserve production configuration/key/uploads/installed.lock; public/ docroot; maintenance-mode php bin/migrate.php and php bin/preflight.php; retain DBA audit guards and least-privilege DB access. Recheck PWA activation/refresh after deployment. See DEPLOYMENT.txt and RELEASE-STATUS.txt for partial localization and all earlier acceptance gates. Portable PHP test suites ship in tests/ and refuse non-*_test databases.


===== Integration and route regression =====
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/verify
PASS Route handler exists /security
PASS Route handler exists /admin/access
PASS Route handler exists /hr
PASS Route handler exists /hr/schedule
PASS Route handler exists /hr/attendance
PASS Route handler exists /hr/payroll
PASS Route handler exists /hr/payroll/{id}
PASS Route handler exists /properties
PASS Route handler exists /translations
PASS Route handler exists /translations/export
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}
PASS Route handler exists /login/verify
PASS Route handler exists /security/{action}
PASS Route handler exists /admin/access/{action}
PASS Route handler exists /hr/{module}/{action}
PASS Route handler exists /properties/switch
PASS Route handler exists /properties/admin/{action}
PASS Route handler exists /locale
PASS Route handler exists /translations/{action}

TOTAL 138 assertions passed; 92 registered routes.


===== Financial/tenant hardening =====
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.


===== Identity/access/ledger =====
PASS RFC 6238 published vector 59
PASS RFC 6238 published vector 1111111109
PASS RFC 6238 published vector 1111111111
PASS RFC 6238 published vector 1234567890
PASS RFC 6238 published vector 2000000000
PASS RFC 6238 published vector 20000000000
PASS Generated TOTP secret has 160-bit base32 form
PASS Current TOTP matches
PASS Used counter cannot match again
PASS Non-numeric TOTP rejected
PASS Out-of-window TOTP rejected
PASS TOTP secret round-trips through authenticated encryption
PASS Tampered encrypted secret is rejected
PASS Enrollment requires the current password
PASS Enrollment issues a local authenticator URI
PASS Enrollment issues ten unique recovery codes
PASS Enrollment stores encrypted secret and removes plaintext slot
PASS Enrollment revokes older sessions and upgrades current session
PASS Database stores only hashes of recovery codes
PASS Password alone grants no authenticated session for enrolled user
PASS Fresh TOTP completes password sign-in
PASS Verified sign-in TOTP cannot be replayed
PASS Repeated password login returns challenge
PASS Unused recovery code completes sign-in
PASS Recovery code works once only
PASS Enrolled settings administrator can enforce property 2FA policy
PASS Required policy prevents disabling 2FA
PASS Custom role belongs to current property
PASS Staff account is assigned selected custom role
PASS Permission update revokes sessions of assigned users
PASS Stale role version rejected
PASS System role templates are immutable through administration
PASS Delegated role administrator cannot grant unheld financial permission
PASS Non-super administrator cannot assign super-admin
PASS Delegated administrator cannot alter super administrator
PASS Administrator cannot edit own assigned role
PASS Foreign-property role cannot be assigned
PASS Administrator cannot disable own account
PASS Cross-property user edits rejected
PASS Authorized staff deactivation persists
PASS Stale user version rejected
PASS Property policy sends unenrolled password-valid user to enrollment
PASS Recovery regeneration issues ten replacement codes
PASS Regeneration invalidates every old recovery code
PASS 2FA disable removes encrypted secret and recovery codes
PASS Non-required unenrolled account can use password sign-in
PASS Manual journal requires a replay key
PASS Identical journal replay returns original entry
PASS Changed journal payload cannot reuse a key
PASS Identical expense replay returns original expense
PASS Expense replay creates only one balanced journal
PASS Changed expense payload cannot reuse a key
PASS Expense request key cannot be reused for a journal
PASS Security audit events written without secrets
PASS Audit payloads do not contain authenticator secret
TOTAL 55 identity/access/ledger assertions passed.


===== Identity concurrency =====
PASS Concurrent identical TOTP submissions produce one accepted verification
PASS TOTP replay counter is advanced exactly once
PASS Concurrent identical recovery codes produce one accepted verification
PASS Recovery-code used marker persists once
PASS Concurrent identical ledger submissions return the same entry
PASS Concurrent ledger replay persists a single balanced entry
PASS Concurrent role edits reject the stale version
PASS Custom-role version advances once
TOTAL 8 Phase 7 multi-process assertions passed.


===== HR/payroll =====
PASS Invalid payroll month rejected
PASS Unsupported payroll year rejected
PASS Unknown HR mutation rejected
PASS Missing request key rejected
PASS Employee creation retry returns the original employee
PASS Changed employee payload cannot reuse request key
PASS Employee number includes property and unique identity
PASS Employee directory supports staff without login accounts
PASS Invalid employee email rejected
PASS Negative contract salary rejected
PASS Cross-property linked account rejected
PASS A login account cannot link to two employees
PASS Stale employee write rejected
PASS Overnight shift is derived from end-before-start
PASS Zero-length shift rejected
PASS Shift operational duration limit enforced
PASS Invalid clock time rejected
PASS Break cannot consume the entire shift
PASS Roster stores explicit UTC boundaries
PASS Duplicate employee/date assignment rejected
PASS Overnight roster ends on the next calendar day
PASS Overnight roster overlap rejected across work dates
PASS Changing shift templates preserves existing roster snapshots
PASS Stale shift edit rejected
PASS Attendance subtracts unpaid breaks in integer minutes
PASS Duplicate attendance rejected
PASS Check-in must match the property-local work date
PASS Reverse attendance interval rejected
PASS Future/mismatched attendance rejected
PASS Open attendance cannot be approved
PASS Open attendance prevents overlapping subsequent entries
PASS Stale attendance edit rejected
PASS Draft displays pending-attendance and roster exceptions
PASS Payroll approval blocks unresolved attendance
PASS Approved attendance is protected from direct editing
PASS Roster for approved attendance cannot change
PASS Roster with attendance cannot be removed
PASS Changed attendance invalidates the previous payroll source hash
PASS Draft regeneration updates the same monthly slip
PASS Resolved attendance yields an exception-free payroll draft
PASS Overtime pays only actual minutes beyond snapshotted scheduled paid minutes
PASS Integer payroll computes base, allowance, overtime, percentage and fixed deductions exactly
PASS Stale payroll regeneration rejected
PASS Payroll requires explicit local-review acknowledgement
PASS Draft payroll cannot be marked paid
PASS Payroll approval retry is idempotent
PASS Approved payroll cannot be regenerated
PASS Approved payroll freezes source attendance
PASS Approved payroll freezes new roster records in its month
PASS Approved payroll freezes new attendance in its month
PASS Compensation changes do not rewrite approved historical payslips
PASS External salary payment reference is mandatory
PASS Repeated salary payment mark has one result
PASS Manual payment marker follows draft/approved/paid lifecycle
PASS Paid payroll cannot be marked paid again with another key
PASS Partial-month base salary uses rounded integer calendar-day proration
PASS Deductions exceeding gross are rejected
PASS Invalid percentage deduction rejected
PASS Current/incomplete month cannot be approved
PASS Unused non-frozen roster can be removed
PASS Attendance reopening requires an audit reason
PASS Unfrozen approved attendance supports audited correction
PASS Foreign employee lookup rejected
PASS Foreign shift assignment rejected
PASS Foreign employee payroll generation rejected
PASS Foreign payslip lookup rejected
PASS HR-only operator cannot generate payroll
PASS HR-only operator cannot read salary slips
PASS HR-only operator cannot set compensation
PASS HR-only employee registration defaults compensation without exposing it
PASS Non-payroll directory rendering omits salary controls
PASS Employee names are HTML-escaped
PASS Directory listing excludes foreign property employee data
PASS HR controller renders index inside existing shell
PASS HR controller renders schedule inside existing shell
PASS HR controller renders attendance inside existing shell
PASS HR controller renders payroll inside existing shell
PASS Printable paid slip uses immutable payroll amounts and manual receipt reference
PASS Nonexistent spring-forward wall time rejected
PASS Ambiguous fall-back wall time rejected
PASS Unambiguous DST property-local input converts to UTC
PASS Audit insertion failure aborts HR mutation
PASS HR row and request key roll back together with audit failure
PASS Payroll manual payment markers do not silently post general-ledger entries
PASS HR workflows emit transactional audit events
TOTAL 85 HR/payroll assertions passed.


===== HR concurrency =====
PASS Concurrent duplicate roster writes produce one successful assignment
PASS Concurrent roster requests persist one row
PASS Simultaneous identical payroll-generation requests return one draft identity
PASS Concurrent payroll generation persists one monthly payslip
PASS Payroll approval and attendance creation serialize; exactly one wins
PASS Approval never commits a stale snapshot alongside new pending attendance
PASS Concurrent identical salary-payment markers resolve idempotently
PASS Concurrent salary-payment replay creates one payment audit event
PASS Session revocation is rechecked inside the HR mutation transaction
TOTAL 9 HR concurrency assertions passed.


===== Assigned-property service/views =====
PASS Existing user receives implicit home access without migration backfill
PASS Super Admin does not automatically receive operational access to every property
PASS Home system Super Admin has explicit central provisioning authority
PASS Property creation retries return one property
PASS Repeated property request inserts one row
PASS Property request key cannot bind a different payload
PASS Creating a property does not switch the active context
PASS Creating a property grants explicit additional access to its creator
PASS Property creation preserves home ownership
PASS Invalid property input rejected: property_code
PASS Invalid property input rejected: timezone
PASS Invalid property input rejected: currency
PASS Invalid property input rejected: tax_rate
PASS Invalid property input rejected: tax_rate
PASS Invalid property input rejected: type
PASS Duplicate property code rejected
PASS Unassigned Super Admin cannot switch into an unrelated property
PASS Unknown property switch rejected
PASS Switch selects the assigned property and its currency
PASS Switch applies the target property timezone
PASS Property switch regenerates session identifier
PASS Property switch invalidates tokens from all previously open forms
PASS Central provisioning requires returning to the home property
PASS Switched Super Admin cannot provision from the wrong home context
PASS Account creation through ordinary Users and Roles is home-context only
PASS System role permissions apply in the explicitly assigned active property
PASS Switched context cannot access home guest records
PASS Switch back restores home context
PASS Additional membership grants invalidate old target-user sessions
PASS Repeated membership grant does not revoke sessions twice
PASS Stale membership edits rejected
PASS Implicit home access cannot be modified as an additional grant
PASS Assigned non-admin can see its two accessible properties
PASS Receptionist cannot invoke central provisioning
PASS Branch switching retains the receptionist role without privilege escalation
PASS Mutation rechecks user session version after obtaining the property mutex
PASS Stale-session mutation leaves no row behind
PASS Revoked explicit property selection fails closed without home fallback
PASS Revoked context has no role permissions
PASS Revoked membership cannot perform a tenant mutation
PASS Regrant advances membership version instead of replacing provenance
PASS Property-owned custom roles cannot receive cross-property grants
PASS Even a raw invalid grant cannot expose another property to a custom role
PASS Foreign custom-role context fails closed independently of stored membership
PASS Central provisioning can create correctly owned branch-local staff
PASS Branch-local initial password is hashed
PASS Branch provisioning cannot mint another Super Admin
PASS Membership administration cannot take over foreign-owned accounts
PASS Self-revocation of additional access is blocked
PASS Central staff provisioning preserves explicit operational access boundaries
PASS Target requiring 2FA refuses password-only sign-in
PASS Assigned-property 2FA policy applies even while the user is at home
PASS Verified enrolled sign-in may switch into a 2FA-required property
PASS Deactivated selected property fails closed
PASS Explicit zero selection cannot silently fall back to home
PASS Property names escape HTML in cards and administration forms
PASS Application shell exposes active-property context for operators and AJAX
PASS Property audit failure aborts provisioning
PASS Property, creator membership and request record roll back with audit failure
PASS Property switches are recorded in the transactional audit log
PASS Changing a user role revokes additional memberships pending explicit reapproval
TOTAL 61 property-access assertions passed.


===== Property concurrency =====
PASS Concurrent same-key property creation returns one branch identity
PASS Concurrent property creation persists one branch
PASS Concurrent identical membership grants both resolve successfully
PASS Concurrent membership retry revokes target sessions once
PASS Concurrent membership grants persist one membership
PASS Membership revocation succeeds against a competing property writer
PASS Competing write either commits before revocation or is rejected; none commits afterward
PASS Revocation leaves membership inactive after the race
PASS Previously valid branch session cannot write after committed revocation
TOTAL 9 property concurrency assertions passed.


===== New catalogue and localization service/view assertions =====
PASS Versioned English catalogue contains 75 registered keys
PASS Catalogue key coverage matches English for en
PASS Valid UTF-8 text and placeholders en:nav.dashboard
PASS Valid UTF-8 text and placeholders en:nav.calendar
PASS Valid UTF-8 text and placeholders en:nav.reservations
PASS Valid UTF-8 text and placeholders en:nav.rooms
PASS Valid UTF-8 text and placeholders en:nav.guests
PASS Valid UTF-8 text and placeholders en:nav.front_office
PASS Valid UTF-8 text and placeholders en:nav.night_audit
PASS Valid UTF-8 text and placeholders en:nav.housekeeping
PASS Valid UTF-8 text and placeholders en:nav.pos
PASS Valid UTF-8 text and placeholders en:nav.kitchen
PASS Valid UTF-8 text and placeholders en:nav.inventory
PASS Valid UTF-8 text and placeholders en:nav.accounting
PASS Valid UTF-8 text and placeholders en:nav.hr
PASS Valid UTF-8 text and placeholders en:nav.crm
PASS Valid UTF-8 text and placeholders en:nav.maintenance
PASS Valid UTF-8 text and placeholders en:nav.events
PASS Valid UTF-8 text and placeholders en:nav.pricing
PASS Valid UTF-8 text and placeholders en:nav.reports
PASS Valid UTF-8 text and placeholders en:nav.properties
PASS Valid UTF-8 text and placeholders en:nav.security
PASS Valid UTF-8 text and placeholders en:nav.access
PASS Valid UTF-8 text and placeholders en:nav.translations
PASS Valid UTF-8 text and placeholders en:common.sign_out
PASS Valid UTF-8 text and placeholders en:common.language
PASS Valid UTF-8 text and placeholders en:common.apply
PASS Valid UTF-8 text and placeholders en:common.save
PASS Valid UTF-8 text and placeholders en:common.reset
PASS Valid UTF-8 text and placeholders en:common.user
PASS Valid UTF-8 text and placeholders en:common.refresh
PASS Valid UTF-8 text and placeholders en:common.current_password
PASS Valid UTF-8 text and placeholders en:common.factor
PASS Valid UTF-8 text and placeholders en:shell.toggle_nav
PASS Valid UTF-8 text and placeholders en:shell.active_property
PASS Valid UTF-8 text and placeholders en:theme.title
PASS Valid UTF-8 text and placeholders en:theme.primary
PASS Valid UTF-8 text and placeholders en:theme.accent
PASS Valid UTF-8 text and placeholders en:theme.background
PASS Valid UTF-8 text and placeholders en:theme.surface
PASS Valid UTF-8 text and placeholders en:auth.tagline
PASS Valid UTF-8 text and placeholders en:auth.email
PASS Valid UTF-8 text and placeholders en:auth.password
PASS Valid UTF-8 text and placeholders en:auth.sign_in
PASS Valid UTF-8 text and placeholders en:auth.challenge
PASS Valid UTF-8 text and placeholders en:auth.instructions
PASS Valid UTF-8 text and placeholders en:auth.factor
PASS Valid UTF-8 text and placeholders en:auth.verify
PASS Valid UTF-8 text and placeholders en:auth.restart
PASS Valid UTF-8 text and placeholders en:auth.invalid
PASS Valid UTF-8 text and placeholders en:auth.throttled
PASS Valid UTF-8 text and placeholders en:dashboard.title
PASS Valid UTF-8 text and placeholders en:dashboard.welcome
PASS Valid UTF-8 text and placeholders en:dashboard.occupancy
PASS Valid UTF-8 text and placeholders en:dashboard.arrivals
PASS Valid UTF-8 text and placeholders en:dashboard.in_house
PASS Valid UTF-8 text and placeholders en:dashboard.revenue
PASS Valid UTF-8 text and placeholders en:dashboard.workspace
PASS Valid UTF-8 text and placeholders en:dashboard.guidance
PASS Valid UTF-8 text and placeholders en:dashboard.deployment
PASS Valid UTF-8 text and placeholders en:i18n.title
PASS Valid UTF-8 text and placeholders en:i18n.scope
PASS Valid UTF-8 text and placeholders en:i18n.search
PASS Valid UTF-8 text and placeholders en:i18n.key
PASS Valid UTF-8 text and placeholders en:i18n.source
PASS Valid UTF-8 text and placeholders en:i18n.builtin
PASS Valid UTF-8 text and placeholders en:i18n.override
PASS Valid UTF-8 text and placeholders en:i18n.edit
PASS Valid UTF-8 text and placeholders en:i18n.remove
PASS Valid UTF-8 text and placeholders en:i18n.saved
PASS Valid UTF-8 text and placeholders en:i18n.deleted
PASS Valid UTF-8 text and placeholders en:i18n.placeholders
PASS Valid UTF-8 text and placeholders en:i18n.results
PASS Valid UTF-8 text and placeholders en:i18n.previous
PASS Valid UTF-8 text and placeholders en:i18n.next
PASS Valid UTF-8 text and placeholders en:i18n.export
PASS Valid UTF-8 text and placeholders en:i18n.fallback_notice
PASS Catalogue key coverage matches English for fr
PASS Valid UTF-8 text and placeholders fr:nav.dashboard
PASS Valid UTF-8 text and placeholders fr:nav.calendar
PASS Valid UTF-8 text and placeholders fr:nav.reservations
PASS Valid UTF-8 text and placeholders fr:nav.rooms
PASS Valid UTF-8 text and placeholders fr:nav.guests
PASS Valid UTF-8 text and placeholders fr:nav.front_office
PASS Valid UTF-8 text and placeholders fr:nav.night_audit
PASS Valid UTF-8 text and placeholders fr:nav.housekeeping
PASS Valid UTF-8 text and placeholders fr:nav.pos
PASS Valid UTF-8 text and placeholders fr:nav.kitchen
PASS Valid UTF-8 text and placeholders fr:nav.inventory
PASS Valid UTF-8 text and placeholders fr:nav.accounting
PASS Valid UTF-8 text and placeholders fr:nav.hr
PASS Valid UTF-8 text and placeholders fr:nav.crm
PASS Valid UTF-8 text and placeholders fr:nav.maintenance
PASS Valid UTF-8 text and placeholders fr:nav.events
PASS Valid UTF-8 text and placeholders fr:nav.pricing
PASS Valid UTF-8 text and placeholders fr:nav.reports
PASS Valid UTF-8 text and placeholders fr:nav.properties
PASS Valid UTF-8 text and placeholders fr:nav.security
PASS Valid UTF-8 text and placeholders fr:nav.access
PASS Valid UTF-8 text and placeholders fr:nav.translations
PASS Valid UTF-8 text and placeholders fr:common.sign_out
PASS Valid UTF-8 text and placeholders fr:common.language
PASS Valid UTF-8 text and placeholders fr:common.apply
PASS Valid UTF-8 text and placeholders fr:common.save
PASS Valid UTF-8 text and placeholders fr:common.reset
PASS Valid UTF-8 text and placeholders fr:common.user
PASS Valid UTF-8 text and placeholders fr:common.refresh
PASS Valid UTF-8 text and placeholders fr:common.current_password
PASS Valid UTF-8 text and placeholders fr:common.factor
PASS Valid UTF-8 text and placeholders fr:shell.toggle_nav
PASS Valid UTF-8 text and placeholders fr:shell.active_property
PASS Valid UTF-8 text and placeholders fr:theme.title
PASS Valid UTF-8 text and placeholders fr:theme.primary
PASS Valid UTF-8 text and placeholders fr:theme.accent
PASS Valid UTF-8 text and placeholders fr:theme.background
PASS Valid UTF-8 text and placeholders fr:theme.surface
PASS Valid UTF-8 text and placeholders fr:auth.tagline
PASS Valid UTF-8 text and placeholders fr:auth.email
PASS Valid UTF-8 text and placeholders fr:auth.password
PASS Valid UTF-8 text and placeholders fr:auth.sign_in
PASS Valid UTF-8 text and placeholders fr:auth.challenge
PASS Valid UTF-8 text and placeholders fr:auth.instructions
PASS Valid UTF-8 text and placeholders fr:auth.factor
PASS Valid UTF-8 text and placeholders fr:auth.verify
PASS Valid UTF-8 text and placeholders fr:auth.restart
PASS Valid UTF-8 text and placeholders fr:auth.invalid
PASS Valid UTF-8 text and placeholders fr:auth.throttled
PASS Valid UTF-8 text and placeholders fr:dashboard.title
PASS Valid UTF-8 text and placeholders fr:dashboard.welcome
PASS Valid UTF-8 text and placeholders fr:dashboard.occupancy
PASS Valid UTF-8 text and placeholders fr:dashboard.arrivals
PASS Valid UTF-8 text and placeholders fr:dashboard.in_house
PASS Valid UTF-8 text and placeholders fr:dashboard.revenue
PASS Valid UTF-8 text and placeholders fr:dashboard.workspace
PASS Valid UTF-8 text and placeholders fr:dashboard.guidance
PASS Valid UTF-8 text and placeholders fr:dashboard.deployment
PASS Valid UTF-8 text and placeholders fr:i18n.title
PASS Valid UTF-8 text and placeholders fr:i18n.scope
PASS Valid UTF-8 text and placeholders fr:i18n.search
PASS Valid UTF-8 text and placeholders fr:i18n.key
PASS Valid UTF-8 text and placeholders fr:i18n.source
PASS Valid UTF-8 text and placeholders fr:i18n.builtin
PASS Valid UTF-8 text and placeholders fr:i18n.override
PASS Valid UTF-8 text and placeholders fr:i18n.edit
PASS Valid UTF-8 text and placeholders fr:i18n.remove
PASS Valid UTF-8 text and placeholders fr:i18n.saved
PASS Valid UTF-8 text and placeholders fr:i18n.deleted
PASS Valid UTF-8 text and placeholders fr:i18n.placeholders
PASS Valid UTF-8 text and placeholders fr:i18n.results
PASS Valid UTF-8 text and placeholders fr:i18n.previous
PASS Valid UTF-8 text and placeholders fr:i18n.next
PASS Valid UTF-8 text and placeholders fr:i18n.export
PASS Valid UTF-8 text and placeholders fr:i18n.fallback_notice
PASS Catalogue key coverage matches English for sw
PASS Valid UTF-8 text and placeholders sw:nav.dashboard
PASS Valid UTF-8 text and placeholders sw:nav.calendar
PASS Valid UTF-8 text and placeholders sw:nav.reservations
PASS Valid UTF-8 text and placeholders sw:nav.rooms
PASS Valid UTF-8 text and placeholders sw:nav.guests
PASS Valid UTF-8 text and placeholders sw:nav.front_office
PASS Valid UTF-8 text and placeholders sw:nav.night_audit
PASS Valid UTF-8 text and placeholders sw:nav.housekeeping
PASS Valid UTF-8 text and placeholders sw:nav.pos
PASS Valid UTF-8 text and placeholders sw:nav.kitchen
PASS Valid UTF-8 text and placeholders sw:nav.inventory
PASS Valid UTF-8 text and placeholders sw:nav.accounting
PASS Valid UTF-8 text and placeholders sw:nav.hr
PASS Valid UTF-8 text and placeholders sw:nav.crm
PASS Valid UTF-8 text and placeholders sw:nav.maintenance
PASS Valid UTF-8 text and placeholders sw:nav.events
PASS Valid UTF-8 text and placeholders sw:nav.pricing
PASS Valid UTF-8 text and placeholders sw:nav.reports
PASS Valid UTF-8 text and placeholders sw:nav.properties
PASS Valid UTF-8 text and placeholders sw:nav.security
PASS Valid UTF-8 text and placeholders sw:nav.access
PASS Valid UTF-8 text and placeholders sw:nav.translations
PASS Valid UTF-8 text and placeholders sw:common.sign_out
PASS Valid UTF-8 text and placeholders sw:common.language
PASS Valid UTF-8 text and placeholders sw:common.apply
PASS Valid UTF-8 text and placeholders sw:common.save
PASS Valid UTF-8 text and placeholders sw:common.reset
PASS Valid UTF-8 text and placeholders sw:common.user
PASS Valid UTF-8 text and placeholders sw:common.refresh
PASS Valid UTF-8 text and placeholders sw:common.current_password
PASS Valid UTF-8 text and placeholders sw:common.factor
PASS Valid UTF-8 text and placeholders sw:shell.toggle_nav
PASS Valid UTF-8 text and placeholders sw:shell.active_property
PASS Valid UTF-8 text and placeholders sw:theme.title
PASS Valid UTF-8 text and placeholders sw:theme.primary
PASS Valid UTF-8 text and placeholders sw:theme.accent
PASS Valid UTF-8 text and placeholders sw:theme.background
PASS Valid UTF-8 text and placeholders sw:theme.surface
PASS Valid UTF-8 text and placeholders sw:auth.tagline
PASS Valid UTF-8 text and placeholders sw:auth.email
PASS Valid UTF-8 text and placeholders sw:auth.password
PASS Valid UTF-8 text and placeholders sw:auth.sign_in
PASS Valid UTF-8 text and placeholders sw:auth.challenge
PASS Valid UTF-8 text and placeholders sw:auth.instructions
PASS Valid UTF-8 text and placeholders sw:auth.factor
PASS Valid UTF-8 text and placeholders sw:auth.verify
PASS Valid UTF-8 text and placeholders sw:auth.restart
PASS Valid UTF-8 text and placeholders sw:auth.invalid
PASS Valid UTF-8 text and placeholders sw:auth.throttled
PASS Valid UTF-8 text and placeholders sw:dashboard.title
PASS Valid UTF-8 text and placeholders sw:dashboard.welcome
PASS Valid UTF-8 text and placeholders sw:dashboard.occupancy
PASS Valid UTF-8 text and placeholders sw:dashboard.arrivals
PASS Valid UTF-8 text and placeholders sw:dashboard.in_house
PASS Valid UTF-8 text and placeholders sw:dashboard.revenue
PASS Valid UTF-8 text and placeholders sw:dashboard.workspace
PASS Valid UTF-8 text and placeholders sw:dashboard.guidance
PASS Valid UTF-8 text and placeholders sw:dashboard.deployment
PASS Valid UTF-8 text and placeholders sw:i18n.title
PASS Valid UTF-8 text and placeholders sw:i18n.scope
PASS Valid UTF-8 text and placeholders sw:i18n.search
PASS Valid UTF-8 text and placeholders sw:i18n.key
PASS Valid UTF-8 text and placeholders sw:i18n.source
PASS Valid UTF-8 text and placeholders sw:i18n.builtin
PASS Valid UTF-8 text and placeholders sw:i18n.override
PASS Valid UTF-8 text and placeholders sw:i18n.edit
PASS Valid UTF-8 text and placeholders sw:i18n.remove
PASS Valid UTF-8 text and placeholders sw:i18n.saved
PASS Valid UTF-8 text and placeholders sw:i18n.deleted
PASS Valid UTF-8 text and placeholders sw:i18n.placeholders
PASS Valid UTF-8 text and placeholders sw:i18n.results
PASS Valid UTF-8 text and placeholders sw:i18n.previous
PASS Valid UTF-8 text and placeholders sw:i18n.next
PASS Valid UTF-8 text and placeholders sw:i18n.export
PASS Valid UTF-8 text and placeholders sw:i18n.fallback_notice
PASS Catalogue key coverage matches English for ar
PASS Valid UTF-8 text and placeholders ar:nav.dashboard
PASS Valid UTF-8 text and placeholders ar:nav.calendar
PASS Valid UTF-8 text and placeholders ar:nav.reservations
PASS Valid UTF-8 text and placeholders ar:nav.rooms
PASS Valid UTF-8 text and placeholders ar:nav.guests
PASS Valid UTF-8 text and placeholders ar:nav.front_office
PASS Valid UTF-8 text and placeholders ar:nav.night_audit
PASS Valid UTF-8 text and placeholders ar:nav.housekeeping
PASS Valid UTF-8 text and placeholders ar:nav.pos
PASS Valid UTF-8 text and placeholders ar:nav.kitchen
PASS Valid UTF-8 text and placeholders ar:nav.inventory
PASS Valid UTF-8 text and placeholders ar:nav.accounting
PASS Valid UTF-8 text and placeholders ar:nav.hr
PASS Valid UTF-8 text and placeholders ar:nav.crm
PASS Valid UTF-8 text and placeholders ar:nav.maintenance
PASS Valid UTF-8 text and placeholders ar:nav.events
PASS Valid UTF-8 text and placeholders ar:nav.pricing
PASS Valid UTF-8 text and placeholders ar:nav.reports
PASS Valid UTF-8 text and placeholders ar:nav.properties
PASS Valid UTF-8 text and placeholders ar:nav.security
PASS Valid UTF-8 text and placeholders ar:nav.access
PASS Valid UTF-8 text and placeholders ar:nav.translations
PASS Valid UTF-8 text and placeholders ar:common.sign_out
PASS Valid UTF-8 text and placeholders ar:common.language
PASS Valid UTF-8 text and placeholders ar:common.apply
PASS Valid UTF-8 text and placeholders ar:common.save
PASS Valid UTF-8 text and placeholders ar:common.reset
PASS Valid UTF-8 text and placeholders ar:common.user
PASS Valid UTF-8 text and placeholders ar:common.refresh
PASS Valid UTF-8 text and placeholders ar:common.current_password
PASS Valid UTF-8 text and placeholders ar:common.factor
PASS Valid UTF-8 text and placeholders ar:shell.toggle_nav
PASS Valid UTF-8 text and placeholders ar:shell.active_property
PASS Valid UTF-8 text and placeholders ar:theme.title
PASS Valid UTF-8 text and placeholders ar:theme.primary
PASS Valid UTF-8 text and placeholders ar:theme.accent
PASS Valid UTF-8 text and placeholders ar:theme.background
PASS Valid UTF-8 text and placeholders ar:theme.surface
PASS Valid UTF-8 text and placeholders ar:auth.tagline
PASS Valid UTF-8 text and placeholders ar:auth.email
PASS Valid UTF-8 text and placeholders ar:auth.password
PASS Valid UTF-8 text and placeholders ar:auth.sign_in
PASS Valid UTF-8 text and placeholders ar:auth.challenge
PASS Valid UTF-8 text and placeholders ar:auth.instructions
PASS Valid UTF-8 text and placeholders ar:auth.factor
PASS Valid UTF-8 text and placeholders ar:auth.verify
PASS Valid UTF-8 text and placeholders ar:auth.restart
PASS Valid UTF-8 text and placeholders ar:auth.invalid
PASS Valid UTF-8 text and placeholders ar:auth.throttled
PASS Valid UTF-8 text and placeholders ar:dashboard.title
PASS Valid UTF-8 text and placeholders ar:dashboard.welcome
PASS Valid UTF-8 text and placeholders ar:dashboard.occupancy
PASS Valid UTF-8 text and placeholders ar:dashboard.arrivals
PASS Valid UTF-8 text and placeholders ar:dashboard.in_house
PASS Valid UTF-8 text and placeholders ar:dashboard.revenue
PASS Valid UTF-8 text and placeholders ar:dashboard.workspace
PASS Valid UTF-8 text and placeholders ar:dashboard.guidance
PASS Valid UTF-8 text and placeholders ar:dashboard.deployment
PASS Valid UTF-8 text and placeholders ar:i18n.title
PASS Valid UTF-8 text and placeholders ar:i18n.scope
PASS Valid UTF-8 text and placeholders ar:i18n.search
PASS Valid UTF-8 text and placeholders ar:i18n.key
PASS Valid UTF-8 text and placeholders ar:i18n.source
PASS Valid UTF-8 text and placeholders ar:i18n.builtin
PASS Valid UTF-8 text and placeholders ar:i18n.override
PASS Valid UTF-8 text and placeholders ar:i18n.edit
PASS Valid UTF-8 text and placeholders ar:i18n.remove
PASS Valid UTF-8 text and placeholders ar:i18n.saved
PASS Valid UTF-8 text and placeholders ar:i18n.deleted
PASS Valid UTF-8 text and placeholders ar:i18n.placeholders
PASS Valid UTF-8 text and placeholders ar:i18n.results
PASS Valid UTF-8 text and placeholders ar:i18n.previous
PASS Valid UTF-8 text and placeholders ar:i18n.next
PASS Valid UTF-8 text and placeholders ar:i18n.export
PASS Valid UTF-8 text and placeholders ar:i18n.fallback_notice
PASS Unsupported locale cannot traverse catalogue paths
PASS Unregistered translation key rejected
PASS Missing source placeholder rejected
PASS Duplicated source placeholder rejected
PASS Introduced placeholder rejected
PASS Empty override rejected
PASS Oversized override rejected
PASS Control character override rejected
PASS Bidi override control rejected
PASS Invalid UTF-8 override rejected
PASS Unsupported stored preference falls back to English
PASS Guest preference selects built-in French without property data
PASS French display number uses narrow-space grouping and decimal comma
PASS Arabic language sets RTL presentation
PASS English number display remains unchanged
PASS Unsupported number display precision rejected
PASS Unregistered lookup returns a stable visible key
PASS Signed-in language preference persists to the existing user column
PASS Kiswahili catalogue is used immediately
PASS Language change never reassigns user home
PASS Unregistered language rejected without preference changes
PASS Property override takes precedence over built-in text
PASS Same-key save retry does not increment the translation version
PASS Request key cannot be reused for another override payload
PASS Stale create rejected after an override already exists
PASS Versioned translation edit updates current rendering
PASS Stale edit rejected
PASS Another property cannot see the first property override
PASS Same key can have an independent override per property
PASS Returning to original context restores only its override
PASS Removing an override restores built-in fallback
PASS Repeated removal does not reapply the transition
PASS Tombstone versions reject stale edits after delete and re-create
PASS Stored markup is rendered only as escaped literal text
PASS Interpolated user names are escaped after substitution
PASS Non-admin staff may save their own language preference
PASS Receptionist cannot modify property translations
PASS Authenticated layout advertises the active language and direction
PASS Actual sidebar rendering escapes malicious override data
PASS Dashboard escapes dynamic name inside translated greeting
PASS Translation administration filters registered catalogue keys
PASS Translation editing controls escape stored override text
PASS Arabic dashboard and shell render with RTL document metadata
PASS Unauthenticated sign-in cannot expose property override text
PASS Password sign-in loads the saved user language rather than the guest choice
PASS Legacy unscoped translation rows remain inactive and cannot leak globally
PASS Audit failure aborts translation override mutation
PASS Override and replay record roll back together on audit failure
PASS Translation changes write transactional audit events without passwords
TOTAL 354 localization assertions passed.


===== New independent-process translation races =====
PASS Concurrent same-key translation saves both resolve successfully
PASS Concurrent save retry persists one override at version zero
PASS Concurrent different edits of one version accept only one writer
PASS Contested translation version advances once
PASS Translation removal racing an edit rejects the stale writer
PASS Delete/edit race preserves monotonic tombstone version
PASS Revoked administrator session cannot update a translation
TOTAL 7 translation concurrency assertions passed.


===== Fresh installer and HTTP =====
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.


===== PMS/CRM/mobile/offline browser =====
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.


===== HR/payroll browser =====
PASS HR directory renders in the existing navy/gold application shell
PASS Employee registration form writes a property-scoped staff record
PASS Employee directory persistence verified independently in MySQL
PASS Shift creation form saves local shift and unpaid break
PASS Roster submission retains its historical schedule filter
PASS Attendance submission retains the recorded payroll month
PASS Attendance approval form commits its reviewed status
PASS Payroll draft form generates exact monthly net pay with overtime
PASS Generated payslip is explicitly a draft until reviewed
PASS Payroll approval rejects incorrect reauthentication without changing its status
PASS Reviewed payroll approval requires and accepts the current password
PASS Manual salary-payment recording produces a frozen paid payslip
PASS Payslip print stylesheet hides navigation and retains the document
PASS Print/Save PDF control invokes browser printing
PASS HR mutation rejects missing CSRF token
PASS Invalid payroll-period query returns HTTP 422 without a fatal error
PASS HTTP attendance correction cannot alter a paid payroll period
PASS Cross-property payslip URL returns HTTP 404
PASS HR directory does not expose foreign-property employees
PASS Role change revokes the browser session before HR access
PASS HR-only account does not receive salary input fields
PASS HR-only account is denied the payroll screen
PASS HR-only account is denied printable payslips
PASS HR-only account cannot invoke payroll-generation POST directly
PASS Employee page fits a mobile viewport without horizontal overflow
PASS HR workflows produce no uncaught browser JavaScript errors
PASS Service worker does not persist authenticated HR or salary pages
TOTAL 27 HR browser/HTTP checks passed.


===== Identity browser =====
PASS Browser creates property-owned role with selected permissions
PASS Browser creates staff account assigned to custom role
PASS Custom-role staff can open granted CRM module
PASS Custom-role staff cannot open access administration
PASS Role edit revokes the existing staff session
PASS Reauthenticated staff loses revoked CRM permission
PASS Enrollment renders local QR payload and manual setup key
PASS Confirmed enrollment displays ten one-use recovery codes
PASS Enabling two-factor revokes previously active browser session
PASS Recovery codes disappear after their one-time display
PASS Enrolled password sign-in requires a second-factor challenge
PASS Incomplete challenge cannot reach dashboard
PASS Current authenticator code completes browser sign-in
PASS One-use recovery code completes browser sign-in
PASS Used recovery code cannot be replayed in the browser
PASS Settings administrator enforces property-wide enrollment policy
PASS Required policy restricts unenrolled staff to enrollment page
PASS Enrolled administrator retains access administration
PASS Repeated journal form submission creates one journal entry
PASS Repeated expense form submission creates one expense row
PASS Authenticator and recovery pages are never cached by service worker
PASS No uncaught JavaScript errors in identity workflows
PASS QR and identity screens make no external asset requests
TOTAL 23 Phase 7 browser checks passed.


===== Property-switching browser =====
PASS Property access page renders inside the existing shell
PASS Property creation requires current-password confirmation
PASS Property form creates an isolated resort with configured currency, tax and timezone
PASS Central staff provisioning assigns a new login to its branch home property
PASS Switch updates the global active-property badge
PASS Central administration is hidden while the administrator is switched away from home
PASS Ordinary user/role administration rejects switched-home context
PASS Existing CRM mutations use the selected property rather than the user home
PASS Old-tab native mutation is rejected after property-switch token rotation
PASS Old-tab AJAX request returns a property-context conflict
PASS Shared AJAX helper gives a refresh-required error for stale context
PASS Home CRM collection excludes branch records after switching back
PASS Returning home restores central provisioning controls
PASS Unassigned receptionist cannot enumerate another operational property
PASS Granting membership invalidates the target user previous session
PASS Assigned receptionist can switch to its newly granted branch
PASS Switching never grants accounting permissions to a receptionist
PASS Revocation terminates an already switched branch session
PASS Revoked additional membership is absent on the next sign-in
PASS Branch-local staff signs in directly to its own home property
PASS Target property 2FA requirement blocks password-only switching
PASS Properties and membership controls fit the mobile viewport
PASS Property switching and administration produce no uncaught browser JavaScript errors
PASS Service worker does not persist authenticated property membership pages
TOTAL 24 property browser/HTTP checks passed.


===== Security and tenant HTTP =====
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 bypass the second-factor challenge
PASS HTTP login throttle survives six fresh cookie jars
TOTAL 16 security HTTP checks passed.


===== New localization/RTL browser and HTTP =====
PASS Guest selector localizes the sign-in page in French
PASS Translated sign-in labels retain the original credential fields
PASS Successful sign-in loads saved account language over guest preference
PASS Authenticated selector localizes dashboard and shared navigation
PASS Language choice persists to the current user preference
PASS French navigation uses localized labels without changing reservation routes
PASS HTML response declares the active Content-Language
PASS Saved preference survives logout and a new sign-in
PASS Kiswahili dashboard renders its registered catalogue
PASS Arabic dashboard switches document direction to RTL
PASS RTL sidebar is anchored to the right on desktop
PASS Arabic dashboard fits a mobile viewport without horizontal overflow
PASS RTL mobile sidebar opens into the viewport
PASS Translation administration is localized and available to settings administrators
PASS Editing an override requires current-password confirmation
PASS Saved override immediately changes the current property navigation label
PASS Retrying the exact translation request does not increment its version
PASS Override markup displays as literal text rather than executing HTML
PASS Translation editor rejects a missing dynamic placeholder
PASS Authorized JSON export contains active property overrides only
PASS Property switch preserves user language but does not inherit another property override
PASS Removing the override restores built-in French text
PASS Unsupported locale or traversal input is rejected
PASS Language redirect allowlist blocks external return targets
PASS Language selection requires a valid CSRF token
PASS Receptionist cannot access translation administration
PASS Receptionist cannot export property translation data
PASS Receptionist cannot submit an override mutation directly
PASS Non-admin staff can still change their own UI language
PASS Localized screens and RTL interactions produce no uncaught JavaScript errors
PASS Service worker does not persist private translation administration pages
TOTAL 31 localization browser/HTTP checks passed.


===== Earlier upgrade and SQL backup/restore =====
PASS Archived Phase6 database upgrades through Phase7
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.


===== Application-key and recovery operators =====
PASS Key provisioning creates once and never silently rotates an existing key
PASS Provisioned application key is owner-readable only
PASS Emergency recovery refuses missing confirmation and replacement password
PASS Confirmed operator recovery completes through shipped CLI
PASS Recovery resets enrollment, revokes sessions and replaces password atomically
PASS Emergency recovery records a DBA audit event
TOTAL 6 key/recovery operator checks passed.


===== Archived Phase7 HR upgrade =====
PASS Actual archived Phase7 schema upgrades through Phase8
PASS Phase8 upgrade rerun is idempotent
PASS Legacy linked employee names backfill only from matching-property accounts
PASS Unknown legacy staff identity and end dates are preserved for reconciliation
PASS Legacy shift ownership inferred from unambiguous single-property roster usage
PASS Shared and unused legacy shifts remain unassigned rather than guessing ownership
PASS Migration never silently approves historical attendance
PASS Historical settled payroll is preserved without inventing calculation provenance
PASS Readiness preflight blocks Legacy employee identity and employment-end dates reconciled
PASS Readiness preflight blocks Legacy shift ownership reconciled
PASS Readiness preflight blocks Legacy roster property and schedule snapshots reconciled
PASS Readiness preflight blocks Legacy settled payroll has reviewed snapshot provenance
PASS Interrupted-migration replay reuses metadata without duplicate columns or lost staff
TOTAL 13 HR upgrade checks passed.


===== Archived Phase8 property upgrade =====
PASS Actual archived Phase8 schema upgrades through Phase9
PASS Phase9 migration rerun is idempotent
PASS Upgrade preserves existing user homes, roles, hashes, session versions and guest ownership
PASS Upgrade grants no additional property access implicitly
PASS Membership and idempotent provisioning tables are created
PASS Interrupted Phase9 metadata replay succeeds without destructive changes
TOTAL 6 Phase9 upgrade checks passed.


===== New archived Phase9 localization upgrade =====
PASS Actual archived Phase9 schema upgrades through Phase10
PASS Phase10 migration rerun is idempotent
PASS Upgrade preserves existing users, registered/legacy locales, memberships and global translations
PASS Legacy global messages are not silently assigned to every property
PASS Scoped translation and replay tables are created
PASS Interrupted Phase10 metadata replay is safe
TOTAL 6 Phase10 upgrade checks passed.

