Changelog

Last generated 2026-07-13 · window 2026-07-12T18:02:00Z–2026-07-13T18:01:03Z

2026-07-13#

Feature

  • Revenue Management Home + Portfolio data plane — New Inertia route GET /revenue-management/home/{facility?} becomes the RM nav landing page. Home hydrates from the engine portfolioPage bundle: corp-wide facilities table (occupancy, RevPAF, opportunity, churn, auto-apply, engine-connected status), portfolio health KPIs, occupancy trend, and optional value_report (realised uplift attribution). Surfaces the engine does not yet feed render honest not-wired placeholders rather than fabricated zeros. Hub cards launch Approval Centre / Rules / Portfolio; AttentionStrip shows portfolio-wide pending and below-market counts from bulk-pricing. AppDefinition.relatedRoutes keeps Portfolio gated on the same REV_MAN_HOME Pennant key after the nav repoint. Global INTERNAL now wins over the entitlement gate for staff preview (engine still ENABLED-only). Bulk-pricing proxy scopes to activeCorporationCode(). PR #118 · 3783303
  • Bulk Pricing table columns + Why modal — Approval Centre bulk-pricing grid rebuilt to mockup columns: Unit group, Units/avail, Occ, Base (SiteLink standard rate), Competitive, Pricing formula, Unit attributes, Seasonal, Price discovery, Suggested, Override, Action. Engine ListPendingCorp joins live site_units inventory (units_total, units_available, occupancy_pct, base_rate) fresh at read time. Factor columns show $ contribution + % of base; Pricing Formula bundles occupancy+stance+goal so columns reconcile to proposed−base. Collapsible facility groups with Approve-all. Why modal rebuilt as Starting point → factors → Suggested with Stage-as-override / Approve actions. Current (webRate) column deferred as placeholder. PR #124 · f242338

Fix

  • PostHog DAU/WAU — logged-in users only$pageview and feature_viewed capture gated behind identified (authenticated) users. Anonymous landings (Login, ForgotPassword, Invite, Welcome) no longer emit pageviews that inflate unique-user math under person_profiles: identified_only. PR #123 · d89d41f

2026-07-10#

Feature

  • Revenue Management — entitlement split — New per-corp Pennant bool revenue_management_entitled decouples "is this corp provisioned on the engine?" from the legacy revenue_management visibility flag. Entitled corps resolve RM nav/routes to ENABLED; un-entitled see COMING_SOON teaser. Global HIDDEN kill-switch and global INTERNAL admin-pilot gate preserved. Admin enable/onboard, engine-connect, JWT claims, cron, and ensure.rev-mgmt.flag middleware all read entitlement via RevMgmtFlagResolver. RM child apps are read-only in corp admin grid (entitlement-driven). PR #114 · f06169a
  • Application flag availability rankApplicationFlags::availability() derived rank fixes corp COMING_SOON(4) under global ENABLED(3) being incorrectly clamped via raw min(). INTERNAL handled as global-only admin gate; corps cannot assert INTERNAL. Admin grid shows "Resolves to" effective-state hint. (Same PR #114)
  • Scheduled frontend translation sync — New translations:sync command pulls RapidStor v2 frontend bundled translations from public JSON endpoint (/api/translations Page Function) via TranslationImporter. Scheduled daily; hash-gated skip when unchanged. Options: --url, --corp, --dry-run. PR #117 · d3d7715

Migration/DB

  • RM entitlement backfill — One-time migration entitles corps with explicit ENABLED per-corp revenue_management override (not COMING_SOON defaults); global-gated-down opt-ins excluded. (Same PR #114)

Fix

  • Translation sync performance — Batched upserts in SyncFrontendTranslations to reduce DB round-trips. fa5c536
  • Admin corp flag key allowlistUpdateCorporationApplicationFeatureFlags now validates application keys against allConfigurableApplications(), preventing smuggled revenue_management_entitled writes bypassing cold-start onboard tie-break. (Same PR #114)

Config/Infra

  • RAPIDSTOR_FRONTEND_TRANSLATIONS_URL — Configures the public JSON endpoint for translations:sync (config/rapidstor.php). (PR #117)

2026-07-11 – 2026-07-12#

No merged changes in scan window.

2026-07-09#

Feature

  • Admin Data Sync UI — Refactored DataSyncTab.tsx with clearer schedule rows, last-run display, and requirement-aware enable toggles. New ImporterRequirement enum (SITELINK_API, RAPIDSTOR_TOKEN, GOOGLE_INTEGRATION, MTAS_API, BIGQUERY_CONFIG) with shared unmet() helper enforced at manual sync dispatch, app:run-scheduled-syncs, and DataImportJob execution so revoked config cannot keep firing failing jobs. SyncScheduleRow blocks enable when requirements are unmet but always allows disable. PR #111 · a3187e5
  • Translation import scriptapps/web/scripts/import-frontend-translations.mjs reads RapidStor v2 frontend translation trees and loads them into Automate via translations:import. Supports Lando (default), plain Docker, and Docker Swarm targets. 4fd9f5d

Fix

  • INTERNAL parent nav visibilityApplicationMenuBuilder gated parent containers on $effective >= DISABLED, but ApplicationFlags is non-monotonic (INTERNAL=1 below DISABLED=2), so INTERNAL parents like Revenue Management were dropped from the sidebar for admins even though route middleware allowed access. Both parent and child guards now key off "not HIDDEN". PR #110 · 1ac7dfc
  • Widget chat agent prompt refinements — Updated apps/agent-runtime/src/config/agents.ts journey prompt for clearer MCP tool usage (enabled_locations__v1, unit_list_by_type__v1, reservation/enquiry flow). Eval cases and fixture world aligned. 1da617c

2026-07-08#

Feature

  • Tenant Journey — translation overrides — Operators can override booking-journey copy at language, corporation, and location scopes. New models (Language, TranslationKey, Translation), protected API at /api/v1/campaigns/translations/*, public resolver at GET /api/v1/tenant-journey/translations for RapidStor v2. Journey Editor adds click-to-translate against a live preview iframe (VITE_RAPIDSTOR_FRONTEND_URL); dedicated Translations page for scope override grid. Import command journey:import-translations seeds keys from RapidStor configs. PR #73 · ba5ef22
  • RapidStor Settings — native in-app screen — Schema-driven settings UI at /rapidstor-settings/{site?} replaces legacy AngularJS admin for operators when global flag rapidstor_internal_settings is ON/INTERNAL. ~380 fields across tabs with WYSIWYG, per-locale translations editor, feature gating parity (customFeatures, multi-site secondary read-only), and client-side validation matching legacy constraints. SettingsClient authenticates via corp rs_api_token at RapidStor POST /api/v1/authenticate (cached JWT). PR #108 · fdde103
  • Admin screen load timeAdminController refactored with ModuleService to reduce N+1 queries and cache expensive aggregates on the corporations admin page. PR #107 · 42822f5

Migration/DB

  • Translation tables — Migrations create languages, translation_keys, and translations tables for the override chain. (Same PR #73)

Config/Infra

  • VITE_RAPIDSTOR_FRONTEND_URL — Configures RapidStor v2 preview base URL for Tenant Journey editor (replaces hardcoded URL). (Same PR #73)
  • rapidstor_internal_settings global flag — Controls whether RapidStor Settings nav link routes to native screen vs legacy external admin. (Same PR #108)

Internal/refactor

  • Application menu refactor — Declarative AppDefinition, extracted ApplicationStateResolver and ApplicationMenuBuilder; behavior-frozen with characterization + security test suites. Documents four pre-existing route-gate edge cases for follow-up. PR #109 · 02edfad

2026-07-07#

Breaking change

  • Rev-mgmt go-live — anchor precedence tightened — Layer 1 anchor chain is now anchor_ratestandard_rate → skip (standard_rate_unset). The transitional competitor_median fallback is removed: a unit-type with only a legacy competitor-median seed and no SiteLink standard_rate no longer receives recommendations. Flip preflight flags these honestly in missing_anchor_sources. PR #98 · 1b250f2
  • Rev-mgmt go-live — ECRI layer gated off — Existing-customer rate-increase (ECRI) rec emission is disabled unless REV_MGMT_ECRI_ENABLED is explicitly set truthy (default off). ECRI uses fabricated demographic/churn inputs and has no SiteLink push path — not production-ready. (Same PR #98)
  • Rev-mgmt go-live — production boot-guard — Engine server refuses boot in production unless SiteLink wrapper is live, JWT_SECRET is non-empty, and REV_MGMT_DEMO_NOW is unset. Dev/CI opt-out: REV_MGMT_ALLOW_UNSAFE=1. Clock FromEnv now defaults to real wall-clock when REV_MGMT_DEMO_NOW is unset (was frozen 2025-04-15). (Same PR #98)

Feature

  • Approval Centre — unit-type discriminator (ADR-0010 Stage-2) — Bulk-pricing grid rows keyed on _id now show a human discriminator sub-label (Type · Floor N · Features) beneath the non-unique unit_type_code. Engine migration 0023 + Suite mirror add type_name, sitelink_unit_type_id, floor, features to rev_mgmt_unit_type_families; OnboardingService::upsertFamily refreshes them on re-onboard. PR #100 · 0c3c7e3
  • Approval Centre — activity feed end-to-end (PR2) — Engine GET /api/activity (operator events only, SQL-filtered) proxied by Suite at GET /api/v1/revenue-management/activity?facility=. RTK query + groupActivity() renders date-grouped feed in ActivityFeed.tsx. Audit trail now uses structured JWT actor claims (ApproveAs); legacy ParseActor heuristic removed. PR #104 · 02280b3
  • Rev-mgmt PR2 — L1 exploration wiring + competitor staleness — Active explorations wired through engine runs; competitor staleness detection flags outdated competitor data. (Same PR #104)
  • Rev-mgmt go-live — engine-connected gating + scheduler — Engine runs only for engine_connected facilities; undo disabled for disconnected sites. Lando scheduler service runs php artisan schedule:work so app:run-scheduled-syncs fires locally. Manual Admin data syncs mark per-importer SyncSchedule executed. PR #98
  • Agent runtime — standalone TypeScript service (#105) — Extracts managed-agents conversation domain from Laravel into apps/agent-runtime/ with shared @r6digital/agent-contract package. Phase 0–1 ported: turn loop, replay, MCP client, agent profiles, WireTranslator. Dockerized in Lando (agent-runtime.automate.lndo.site) and swarm (agents.r6automate.com). PR #105 · a10e3df

Fix

  • Activity feed SQL filter — Operator event type allowlist pushed into SQL WHERE so internal telemetry (engine.run/skip) cannot starve the feed window. PR #104
  • Agent runtime env loadingapps/agent-runtime/src/main.ts loads .env before bootstrap so local and container starts resolve config correctly. 487fd05

Migration/DB

  • Unit-type family discriminator columns — Engine migration 0023 + Suite 2026_07_06_000001_add_unit_type_family_discriminator add nullable type_name, sitelink_unit_type_id, floor, features to rev_mgmt_unit_type_families. PR #100

Config/Infra

  • Rev-mgmt go-live production secrets — Production env values set for JWT_SECRET, RAPIDSTOR_EXTERNAL_API_TOKEN, and REV_MGMT_ENGINE_URL (webhook secret and internal token intentionally left blank). b6e1530 · 01aaa30

2026-07-06#

Feature

  • Helpdesk Articles — load-all with local search — The Helpdesk Center Articles tab now loads every help article up-front via new GET /api/v1/helpdesk/articles and filters titles in the browser as the user types. Previously the tab showed nothing until the user typed, and each keystroke triggered a debounced CQL search against Confluence over the network. Article bodies are still fetched lazily on drill-in via GET /api/v1/helpdesk/page/{id}. Backend: ConfluenceClient::listArticles() paginates CQL type=page AND ancestor={folderId} order by title, returns { id, title } only, cached 12h with the same tagged cache as search. Frontend: HelpdeskPanel switches from useSearchHelpdeskArticlesQuery to useListHelpdeskArticlesQuery. PR #102 · b2dad20

Fix

  • Helpdesk article list cache guardlistArticles() now throws on malformed Confluence responses instead of caching an empty list for the full 12h TTL (which would blank the Articles tab for all users). Logs a warning when the 1000-result safety cap truncates the list. (Same PR #102)
  • Rev-mgmt approve identity fix — Approving Layer 1 or Layer 2 recommendations now keys Mongo rate overrides, Redis engineCache invalidation, and SiteLink wrapper pushes on rec.UnitTypeID (the RapidStor ObjectId stamped at emit time), not on an _id re-resolved from the reconstructed unit_type_code. Previously ResolveObjectID ran SELECT … WHERE unit_type_code=? with no ORDER BY and returned rows[0], collapsing multiple same-code priced groups onto one arbitrary _id (ADR-0010: e.g. 34 CHAH unit-types → 16 codes). Layer 2 Layer2Run now emits recs with UnitTypeID and derives recommendation IDs from the _id. Code-resolution fallback retained only for legacy un-onboarded recs with empty _id. Known limitation: ClickHouse rev_mgmt_evaluation_windows remains code-keyed; per-_id Layer 2 pricing needs a separate migration. PR #80 · 02bddd4

Docs

  • Generated documentation site — Initial browseable HTML reference for Automate, RapidStor, and StorApp under docs/generated/, with client-side search and per-product changelogs. PR #99 · 4d4f94c

2026-07-05#

Feature

  • Admin Benchmarks tab — New Benchmarks tab on /admin/stats (internal admin). Aggregates booking-journey funnel KPIs across corporations from ClickHouse via FunnelBenchmarkService. Views: by corporation, timezone, fleet baseline, one-vs-rest, top/bottom. Date range picker with partial Inertia reload. Corps with fewer than 50 views excluded from rankings. PR #96 · b5ed9b5

Fix

  • Benchmark error handling — ClickHouse failures degrade to empty tab with error flag instead of 500 on Admin Stats. Credentials moved to HTTP headers in ClickHouseClient. Frontend surfaces reload and server errors. (Same PR #96)