RAR Deployment Runbook
Revenue Architecture Redesign — Staging state + production deployment path
Current State Dashboard — staging snapshot as of Feb 1, 2026
Drew deployed the full RAR codebase to staging on Jan 28, tweaked Lightning pages on Jan 29, then went idle. Three days of no changes. Here's where things stand.
What's Complete
| Component | Count | Status | Notes |
|---|---|---|---|
| Metadata deployed | 257 classes, 57 triggers, 213 LWCs | Done | Full codebase in staging. 19 RAR-specific LWCs. |
| Physical Locations | 78,610 | Done | Created and populated. 83.2% brand-validated. |
| Domains | 30,213 | Done | 99.7% matched. 28,772 Active, 1,288 Invalid, 153 Parked. |
| ALR Junctions | 176,042 | Done | Brand: 62,042 / CC: 75,040 / Operator: 38,960 |
| NS Billing → PL link | 59,423 / 59,482 | 99.9% | 59 orphan NSBAs |
| NS Subscription → PL link | 83,410 / 83,486 | 99.9% | 76 orphan subscriptions |
| Venue → PL link | 101,929 / 118,473 | 86% | 16,544 venues unlinked |
| Website_Root__c | 32,053 accounts | 42.4% | 43,525 accounts without root domain |
| Permission Sets | 9 + 1 PSG | Done | Revenue_Architecture_Full_Access calculated Jan 28 |
| Scheduled Jobs | 3 | Running | Domain maintenance: daily, weekly validation, weekly rematch |
| Kill switches | 22 toggles | Deployed | Master ON, user-level mostly OFF |
What's Blocked or Missing
| Issue | Current Value | Required | Severity |
|---|---|---|---|
| RAR code coverage | 73.8% (5,961 / 8,075 lines) | 75% org-wide for production deploy | P1 |
| Org code coverage | 78.4% (10,022 / 12,781 lines) | 75% | PASS |
| Failing tests | 2 failures (pre-existing, non-RAR) | 0 RAR failures | P1 |
| Account merge strategy | 17,144 pending, no plan | Written decision + implementation | P0 |
| PL ARR__c | 0 / 78,610 populated | All active PLs with ARR | P1 |
| Account_Hierarchy__c | 0 records | Populated hierarchy table | P1 |
| PL Type__c | 0 / 78,610 populated | Classified locations | P1 |
| NS Customer → PL link | 0 / 26,220 | Lookup populated | P1 |
| PL denormalized fields | Operator: 0, CC: 0, Franchisor: 0 | Synced from ALR | P1 |
| Location_Status__c | All NULL | Active/Churned/New | P1 |
| Territory__c / Market__c | All NULL | ZIP-based territory assignment | P1 |
| UAT/CAB sign-off | Verbal only | Written | P0 |
Record Counts — Full Inventory
| Object | Count | Breakdown |
|---|---|---|
Account | 75,578 | Subscriber: 74,102 / Partner: 852 / Franchisor: 609 / Special: 15 |
Physical_Location__c | 78,610 | ARR: all NULL. Type: all NULL. Status: all NULL. |
Domain__c | 30,213 | Active: 28,772 / Invalid: 1,288 / Parked: 153 |
Account_Location_Relationship__c | 176,042 | Brand: 62,042 / CC: 75,040 / Operator: 38,960. All active. All primary. |
Brand__c | 2,550 | 87 custom fields |
NetSuite_Subscription__c | 83,486 | Active: 67,871 ($27.15M ARR) / Terminated: 10,432 / Closed: 2,595 / Draft: 1,370 |
NetSuite_Subscription_Line__c | 215,341 | |
NetSuite_Billing_Account__c | 59,482 | 99.9% linked to PLs |
NetSuite_Customer__c | 26,220 | PL linkage: 0% |
NetSuite_Sales_Order__c | 8,693 | |
Venue__c | 118,473 | 86% linked to PLs (16,544 orphans) |
Invoice_Owner_ARR__c | 20,068 | |
Account_Hierarchy__c | 0 | Table exists but never populated |
Opportunity | 60,360 | Closed Won: 36,447 / Closed Lost: 22,529 |
ALR Resolution Sources
How each ALR junction was resolved. Top sources across all 176,042 records:
| Source | Count | % |
|---|---|---|
LOGO_DIRECT_NSBA | 34,670 | 19.7% |
BILLING_DIRECT_NSBA_MERGED | 27,223 | 15.5% |
BILLING_DIRECT_NSBA | 24,975 | 14.2% |
FRANCHISE_PARENT_NSBA | 20,903 | 11.9% |
FALLBACK_VENUE_ACCOUNT | 18,323 | 10.4% |
LOGO_DIRECT_VENUE | 10,306 | 5.9% |
FRANCHISE_PARENT_NSBA_MERGED | 7,954 | 4.5% |
FALLBACK_DIRECT_NSBA | 7,676 | 4.4% |
| Other (7 sources) | 23,012 | 13.1% |
PL Brand Resolution Sources
How the brand (Account) was determined for each Physical Location:
| Source | Count | % |
|---|---|---|
LOGO_DIRECT_NSBA | 33,669 | 42.8% |
| None (no source tracked) | 16,564 | 21.1% |
LOGO_DIRECT_VENUE | 10,270 | 13.1% |
FALLBACK_DIRECT_NSBA_PENDING | 7,672 | 9.8% |
FRANCHISE_PREFIX_NSBA | 2,872 | 3.7% |
| Other (5 sources) | 7,563 | 9.6% |
Remaining Work — prioritized blockers and tasks
P0 — Must Fix Before Production
Production deployment is impossible until every P0 is resolved. Salesforce will reject the deploy at 7% coverage.
| # | Issue | Current | Target | Est. Effort |
|---|---|---|---|---|
| P0-1 | Code coverage passes 75% gate ✓ Org-wide: 78.4% (10,022 / 12,781). RAR-specific: 73.8% (5,961 / 8,075) — 1.2% below class-level 75% threshold but org-wide passes the Salesforce deploy gate. Coverage was stale at 0%/7% — two full RunLocalTests runs on Feb 2 refreshed the aggregate. No further action required for deployment, though improving RAR coverage to 75%+ would provide additional safety margin. |
74% RAR / 78% org ✓ | ≥75% org-wide | Done |
| P0-2 | 2 failing tests (pre-existing, non-RAR)ConvertLeadApexTest.testConvertLead and testConvertLeadWithoutOpportunity — both fail with Same value: null. These are legacy Rockbot tests, not RAR code. 9 RAR test failures were resolved: DomainMaintenanceScheduler fix deployed, others were passing after data refresh. Coordinate with Kevin to fix or quarantine these legacy tests. |
2 failures (legacy) | 0 failures | 2–4 hrs |
| P0-3 | Account merge strategy undecided 17,144 accounts with Merge_Status__c = 'Pending Merge'. 16,952 have no priority set. Only 978 have a confidence score (27 at ≥80%, 931 at 50–79%, 20 below 50%). No one has decided: reparenting or destructive merge? See Merge Strategy. |
No decision | Written decision + code | 2 hrs (decision) + 8–12 hrs (code) |
| P0-4 | UAT/CAB sign-off Kevin and Nick have given verbal approval. Zero written sign-off exists. Get B-01 (UAT) from Kevin/Nick and B-02 (CAB) from Aron before touching production. |
Verbal | Written | 2 hrs |
| P0-5 | Rollback plan untesteddestructiveChanges.xml exists but has never been executed. Need a dry-run in staging to validate rollback works end-to-end. |
Untested | Validated in staging | 8 hrs |
P1 — Should Fix Before Production
These don't block deployment mechanics but will make production data incomplete or misleading.
| # | Issue | Fix | Est. Effort |
|---|---|---|---|
| P1-1 | PL ARR__c all NULL 78,610 PLs with no ARR value. The Attributed_ARR__c formula on ALR calculates PL.ARR__c × Attribution_% = $0 × 100% = $0 for every junction. The weighted attribution model is non-functional. |
Either populate ARR__c from Subscription_ARR__c rollup, or change the Attributed_ARR__c formula to reference Subscription_ARR__c directly. |
4–8 hrs |
| P1-2 | Account_Hierarchy__c empty 0 records. The pre-computed hierarchy table designed to eliminate recursive SOQL provides zero value. DomainTriggerHandler is still doing SOQL-in-loop hierarchy traversal. |
Run AccountHierarchyBatchJob: Database.executeBatch(new AccountHierarchyBatchJob(), 200); |
2–4 hrs |
| P1-3 | PL denormalized fields emptyOperator__c, Contracting_Customer__c, Franchisor__c all NULL on every PL. 176K ALR junctions exist but the sync-back never ran. |
Run PLJunctionSyncService batch to populate from ALR records. |
4–8 hrs |
| P1-4 | Location_Status__c all NULL Can't distinguish active from churned locations. 29,775 PLs (37.9%) have zero Subscription_ARR — probably churned, but no way to confirm without status. |
Run LocationStatusService batch to derive status from subscription data. |
4–6 hrs |
| P1-5 | Territory/Market all NULL Zero geographic segmentation. No territory-based reporting possible. |
Run ZIP enrichment + territory assignment using Territory_Mapping__mdt. |
2–4 hrs |
| P1-6 | PL Type__c all NULL Picklist values defined (Franchisee, Franchisor, Location, Other) but never assigned. |
Batch assignment based on Account RecordType and franchise hierarchy. | 2–4 hrs |
| P1-7 | NetSuite_Customer__c → PL linkage at 0% 26,220 NS Customer records. Lookup field exists on PL but never populated. |
Build linkage batch: match NS Customer to PL via NSBA relationship chain. | 4–8 hrs |
| P1-8 | ARR attribution weights never applied All 176,042 ALRs have ARR_Attribution_Percent__c = 100%. The 50/30/15/5 weighting (Brand/Operator/CC/Owner) has never been executed. Finance has never validated the weights. |
Get weight validation from Nick/Aron. Then run ArrAttributionService. |
2 hrs (validation) + 4 hrs (execution) |
| P1-9 | Dual resolution systemsPhysicalLocationEnrichmentService (P1-P5 waterfall) and AccountResolutionService (weighted consensus) both create ALR junctions. They can resolve the same PL to different Brand accounts. |
Deprecate waterfall. Route all resolution through consensus algorithm. | 24–32 hrs |
P2 — Nice to Have
| # | Issue | Notes |
|---|---|---|
| P2-1 | Website_Root__c only 42.4% | 43,525 accounts without root domain. Re-run backfill for accounts with no Website field — may need manual assignment. |
| P2-2 | ALR confidence improvement | All 176K ALRs have confidence populated but most are low (0.17–0.47). Some reach 1.0 with high Resolution_Score. Build review queue for bottom quartile. |
| P2-3 | Brand validation backlog | 13,215 PLs (16.8%) pending review. Build review workflow or batch-validate using confidence thresholds. |
| P2-4 | 16,544 orphan venues | 14% of venues not linked to PLs. Investigate if inactive/expired. If active, they represent missing ARR. |
| P2-5 | 135 orphan billing records | 59 NSBAs + 76 NS Subscriptions with no PL link. Estimated $57–75K in unattributed ARR. |
| P2-6 | LWC Jest tests | 19 RAR LWCs including 700+ line rarAdminConsole have zero client-side tests. |
| P2-7 | Batch job monitoring | No email/Slack notification on batch failure. Failures go unnoticed. |
Test Failure Analysis — 2 legacy failures remaining, 9 RAR fixes resolved
RunLocalTests completed: 1,081 pass, 2 fail. All 11 original RAR test failures are resolved. The 2 remaining failures are pre-existing Rockbot legacy tests unrelated to RAR.
Remaining Failures (2 — Non-RAR)
| # | Class.Method | Error | Root Cause | Owner |
|---|---|---|---|---|
| 1 | ConvertLeadApexTest. |
Assertion Failed: Same value: null |
Pre-existing legacy test. The lead conversion handler expects a non-null value that isn't being set in the test's execution context. Not RAR code — likely broken by a prior Rockbot deploy. | Kevin Grothe (Rockbot internal) |
| 2 | ConvertLeadApexTest. |
Assertion Failed: Same value: null |
Same class, same root cause as #1. Both methods test lead conversion which is outside RAR scope. | Kevin Grothe (Rockbot internal) |
Resolved Failures (9 RAR Tests — All Fixed)
These failures were identified on Feb 1 and resolved via production class fix (DomainMaintenanceScheduler) and test data corrections. Full test run on Feb 2 confirms all passing.
| # | Class.Method | Original Error | Resolution |
|---|---|---|---|
| 1 | DomainMaintenanceSchedulerTest. |
Expected 3 jobs, got 6 | Fixed Modified production class to query only 3 specific job names instead of LIKE 'Domain%' |
| 2–3 | ALRTriggerHandlerTest (both methods) |
Resolution source: null | Passing Queueable execution now completing within test context |
| 4 | BrandResolutionControllerTest |
Expected 3 waterfall steps, Actual 1 | Passing Test expectations aligned with refactored waterfall |
| 5–7 | PhysicalLocationLinkServiceTest (3 methods) |
Expected 1 PL, Actual 2 | Passing Address matching rules firing correctly after data refresh |
| 8 | PhysicalLocationCreateBatchTest |
Should reuse existing location | Passing Same matching rule resolution as #5–7 |
| 9 | UltimateParentBatchJobTest |
Merge_Status__c restricted picklist error | Passing Picklist value corrected in test data |
Code Coverage — 78.4% org-wide ✓, 73.8% RAR (refreshed Feb 2)
Current Numbers (Refreshed Feb 2, 2026)
| Scope | Lines Covered | Lines Uncovered | Coverage | Status |
|---|---|---|---|---|
| Org-wide | 10,022 | 2,759 | 78.4% | PASSES 75% GATE |
| RAR classes (82 classes) | 5,961 | 2,114 | 73.8% | 1.2% short |
| Non-RAR classes | 4,061 | 645 | 86.3% | Strong |
--code-coverage flag). Two full RunLocalTests runs on Feb 2 refreshed the aggregate to accurate levels.
Remaining Coverage Gaps (RAR Classes)
| Class | Covered | Uncovered | Coverage |
|---|---|---|---|
DomainAdminController | 161 | 223 | 42% |
PhysicalLocationMergeBatch | 0 | 174 | 0% |
PhysicalLocationEnrichmentService | 281 | 95 | 75% |
PhysicalLocationDuplicateBatch | 116 | 94 | 55% |
AccountResolutionService | 351 | 82 | 81% |
DomainDuplicateScannerController | 354 | 67 | 84% |
DomainMassVerifyController | 41 | 64 | 39% |
DomainRematchBatch | 160 | 55 | 74% |
These 8 classes represent the remaining ~854 uncovered RAR lines. Improving DomainAdminController and PhysicalLocationMergeBatch alone would push RAR coverage past 75%.
How to Verify Coverage
-- Check refreshed coverage SELECT ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered FROM ApexCodeCoverageAggregate WHERE ApexClassOrTrigger.Name LIKE '%PhysicalLocation%' OR ApexClassOrTrigger.Name LIKE '%AccountResolution%' OR ApexClassOrTrigger.Name LIKE '%Domain%' ORDER BY NumLinesUncovered DESC
Maintaining Coverage Above 75%
Org-wide coverage now passes the deploy gate at 78.4%. To maintain this and improve RAR-specific coverage past 75%:
- Priority targets: Write tests for zero-coverage controller/batch classes listed above.
DomainDuplicateScannerController(421 lines at 0%) alone would push RAR coverage past 75%. - Deployment validation: Use
--test-level RunLocalTestswith--code-coverageto ensure aggregate stays fresh. Stale aggregates caused the original 0%/7% misreading.
Nuclear Option
If legacy tests can't be fixed in time: use @isTest(isParallel=false) annotations to prevent interference, or exclude legacy test classes from the deployment validation. The 2 failing ConvertLeadApexTest methods are outside RAR scope — coordinate with Kevin to fix or quarantine before production.
Production Deployment Checklist — staging → production
Staging has data. Production has nothing. This is a first-time deployment — no RAR objects, fields, classes, or triggers exist in production. The sequence below assumes all P0 items are resolved.
Pre-Deploy (T-14 to T-1)
- P0s resolved: Code coverage ≥75%, 0 failing tests, merge strategy decided, UAT/CAB signed
- Fresh Full Copy sandbox refresh (latest production data)
- Re-run full test suite on refreshed sandbox — confirm 0 failures
- Export production baseline record counts (Account, NSBA, NSS, Venue)
- Test
destructiveChanges.xmlrollback on sandbox — confirm clean removal - Translate sandbox
Merge_Target__cIDs to production IDs usingWebsite_Root__cas join key - Prepare Merge_Target CSV with production Account IDs
- Confirm Boomi sync pause window with Kevin
- Select deployment window (recommended: Friday 6 PM ET → Sunday noon)
- Final go/no-go call: Drew + Kevin + Nick
Phase 0: Prerequisites
Foundation Setup
| Step | Action | Verify |
|---|---|---|
| 0.1 | Enable State/Country picklists Irreversible (likely already enabled) | Setup shows "Enabled" |
| 0.2 | Deploy Global Value Set: Business_Type | Visible in Setup |
| 0.3 | Create Remote Site Setting: dns_google | Active in Setup |
Phase 1: Metadata Deployment
Deploy all RAR objects, fields, Apex, LWCs
| Step | Action | Verify |
|---|---|---|
| 1.1 | Create Automation_Settings__c org default — ALL switches FALSE | Query confirms all FALSE |
| 1.2 | Deploy Territory_Mapping__mdt | Records in Custom Metadata |
| 1.3 | Deploy custom objects: PL → ALR → Domain → Hierarchy (in order) | 4 objects in Object Manager |
| 1.4 | Deploy 24 Account RAR fields | Brand_Parent__c visible |
| 1.5 | Deploy PL lookups on NSBA, NSS, NSSL, Venue | Lookups exist |
| 1.6 | Deploy all Apex classes + triggers | All compile |
| 1.7 | Run full test suite with --code-coverage | ≥75% coverage, 0 RAR failures |
| 1.8 | Deploy LWCs, VF pages, FlexiPages, Permission Sets, Rules | Admin console loads |
| 1.9 | Assign RAR_Admin to Drew + Kevin | Permission Set assigned |
Phase 2: Flow Deactivation
Pause 12 Account flows during migration
Record the EXACT active version number of each flow before deactivating. These flows handle real business processes:
Account_New, Account_Logo_Creation, Account_Logo_Location_Update, Account_Logo_Website_Change, Account_Sync_Account_On_NSC, Account_Change_Account_Team, Account_Update_Logo_Owner, Account_Duplicate_Stamp, Account_Stamp_Customer_Health_Prior_Value, Account_Segment_Logic, Account_Sticky_Account_Name_Owner, Account_Set_Business_Type_From_Group
Phase 3–8: Data Migration
Replicate what staging has — but in production
These phases mirror what Drew already ran in staging. Production volumes will be similar since staging was a Full Copy.
| Phase | Action | Staging Result | Duration |
|---|---|---|---|
| 3 | Website_Root__c backfill | 32,053 accounts populated | 1–2 hrs |
| 4 | Domain creation + validation + Merge_Target CSV load | 30,213 domains (99.7% matched) | 2–4 hrs |
| 5 | PL migration — 10 geographic batches from NSBAs | 78,610 PLs created | 4–8 hrs |
| 6 | Franchisor migration — 609 accounts | RecordType + hierarchy set | 1–2 hrs |
| 7 | Account consolidation — reparenting ~17K accounts | Depends on merge strategy | 4–8 hrs |
| 8 | Junction population — ALR enrichment + attribution | 176,042 ALRs created | 2–4 hrs |
Merge_Target__c CSV must be rebuilt using Website_Root__c or an external ID as the join key. Do NOT copy sandbox IDs into production.
Phase 9: Validation
All integrity checks must pass
- No orphan PLs (
Account__c = null→ 0) - No duplicate domains
- All child accounts have
Top_Level_Parent__c - Domain match rate ≥99%
- Junction coverage — 0 PLs without ALR
- NSBA linkage — <100 unlinked
- NSS linkage — <100 unlinked
- ARR reconciliation within 5% of NetSuite ($27.15M active)
- Brand validation ≥80%
- ALR distribution: Brand ≥62K, CC ≥75K, Operator ≥39K
Phase 10–11: Go-Live
Enable automations, reactivate flows, resume Boomi
| Step | Action |
|---|---|
| 10.1 | Set All_Automations_Enabled__c = TRUE + all individual switches TRUE |
| 10.2 | Schedule DomainValidationBatch (Weekly, Sun 2 AM) |
| 10.3 | Schedule UltimateParentBatchJob (Daily, 3 AM) |
| 10.4 | Schedule PhysicalLocationEnrichmentBatch (Nightly, 4 AM) |
| 10.5 | Smoke test: create NSBA → verify auto PL linkage + ALR creation |
| 11.1 | Reactivate Account flows ONE AT A TIME (reverse order, 5-min gap) |
| 11.2 | Resume Boomi sync (Kevin) |
| 11.3 | Monitor exception logs for 30 minutes → must be 0 |
| 11.4 | Verify RAR Admin Console loads in Revelate app |
Custom_Exception__c records · Governor limit exceptions · Boomi sync failures · User-reported errors → Kill automations → deactivate flows → pause Boomi → assess.
Merge Strategy — 17,144 accounts pending, no decision made
Current State
| Merge Status | Count |
|---|---|
| No status (null) | 57,017 |
| Pending Merge | 17,144 |
| Merged | 805 |
| Active | 612 |
Merge Readiness of the 17,144 Pending
| Metric | Value |
|---|---|
| Have Merge_Target__c set | 17,994 accounts total (includes some non-Pending) |
| Have Merged_Into__c set | 806 |
| Have merge confidence score | 978 of 17,144 (5.7%) |
| Confidence ≥80% | 27 |
| Confidence 50–79% | 931 |
| Confidence <50% | 20 |
| No confidence (null) | 16,166 (94.3%) |
| Have merge priority set | 192 of 17,144 |
| Priority = Auto-Merge | 4 |
| Priority = High | 1 |
| Priority = Normal | 187 |
| Priority = null (unset) | 16,952 |
Option A: Reparenting (Recommended)
Use LocationReparentingService. Both accounts survive. ALR junctions are moved from source to target. Source account gets Merge_Status__c = 'Consolidated Out'. Fully reversible — reparented ALRs are tagged with Resolution_Source__c = 'LocationReparentingService' and have Previous_Account__c for rollback.
- Run PREVIEW mode first → sample 50 accounts
- Execute in batches of 500
- Run
AccountHierarchyBatchJobafter - Run
UltimateParentBatchJobafter
Option B: Database.merge() (NOT Recommended)
Permanently deletes the losing account. Irreversible. On 17K accounts with 94% having no confidence score, this is unacceptable risk. The only valid use case: 4 accounts flagged Auto-Merge with high confidence.
Suggested Approach
Tiered strategy based on available confidence data:
| Tier | Accounts | Action |
|---|---|---|
| Auto-merge (confidence ≥80%) | 27 | Reparent automatically. Low risk. |
| High confidence (50–79%) | 931 | Reparent after spot-check of 50. Medium risk. |
| Low confidence (<50%) | 20 | Manual review before reparenting. |
| No confidence (null) | 16,166 | Do not reparent yet. Run confidence scoring first. Many of these may not be valid merge candidates. |
Data Validation Queries — SOQL with live expected values
Integrity Checks (Staging Baselines)
-- 1. Orphan PLs (expect: 0 — all PLs have Account via Master-Detail) SELECT COUNT() FROM Physical_Location__c WHERE Account__c = null -- 2. Duplicate domains (expect: 0 rows) SELECT Clean_Domain__c, COUNT(Id) cnt FROM Domain__c GROUP BY Clean_Domain__c HAVING COUNT(Id) > 1 -- 3. Child accounts missing ultimate parent (expect: 0) SELECT COUNT() FROM Account WHERE Top_Level_Parent__c = null AND ParentId != null -- 4. PLs without any ALR junction (expect: 0) SELECT COUNT() FROM Physical_Location__c WHERE Id NOT IN (SELECT Physical_Location__c FROM Account_Location_Relationship__c) -- 5. Unlinked NSBAs (staging: 59 of 59,482) SELECT COUNT() FROM NetSuite_Billing_Account__c WHERE Physical_Location__c = null -- 6. Unlinked NS Subscriptions (staging: 76 of 83,486) SELECT COUNT() FROM NetSuite_Subscription__c WHERE Physical_Location__c = null
Record Counts (Staging Baselines)
-- Total PLs (staging: 78,610) SELECT COUNT() FROM Physical_Location__c -- Total Domains (staging: 30,213) SELECT COUNT() FROM Domain__c -- ALR by type (staging: Brand 62,042 / CC 75,040 / Operator 38,960) SELECT Relationship_Type__c, COUNT(Id) cnt FROM Account_Location_Relationship__c GROUP BY Relationship_Type__c -- Domain match status (staging: Matched 30,128 / Manual 83 / No Match 1) SELECT Match_Status__c, COUNT(Id) cnt FROM Domain__c GROUP BY Match_Status__c -- Account merge state SELECT Merge_Status__c, COUNT(Id) cnt FROM Account GROUP BY Merge_Status__c -- Brand validation (staging: Validated 65,395 / Pending 13,215) SELECT Brand_Validation_Status__c, COUNT(Id) cnt FROM Physical_Location__c GROUP BY Brand_Validation_Status__c
ARR Reconciliation
-- NS Subscription ARR by status (Active staging: $27,152,726.93) SELECT Status__c, SUM(ARR__c) arr, COUNT(Id) cnt FROM NetSuite_Subscription__c GROUP BY Status__c -- PL ARR (staging: ALL NULL — this is the P1-1 gap) SELECT COUNT() FROM Physical_Location__c WHERE ARR__c != null -- PL Subscription ARR rollup (staging: 48,835 with ARR > 0) SELECT COUNT() FROM Physical_Location__c WHERE Subscription_ARR__c > 0 -- Top 20 brands by ARR SELECT Account__r.Name, SUM(Physical_Location__r.Subscription_ARR__c) totalARR, COUNT(Physical_Location__c) locations FROM Account_Location_Relationship__c WHERE Relationship_Type__c = 'Brand' AND Is_Active__c = true GROUP BY Account__r.Name ORDER BY SUM(Physical_Location__r.Subscription_ARR__c) DESC LIMIT 20
Linkage Health
-- NSBA → PL linkage (staging: 59,423 of 59,482 = 99.9%) SELECT COUNT() FROM NetSuite_Billing_Account__c WHERE Physical_Location__c != null -- NS Subscription → PL (staging: 83,410 of 83,486 = 99.9%) SELECT COUNT() FROM NetSuite_Subscription__c WHERE Physical_Location__c != null -- Venue → PL (staging: 101,929 of 118,473 = 86.0%) SELECT COUNT() FROM Venue__c WHERE Physical_Location__c != null -- NSBA → PL linkage rate (staging: 66.1%) SELECT COUNT() FROM Physical_Location__c WHERE Id IN (SELECT Physical_Location__c FROM NetSuite_Billing_Account__c) -- Account_Hierarchy (staging: 0 — empty) SELECT COUNT() FROM Account_Hierarchy__c
Code Coverage
-- RAR class coverage (expect: populated after full test run) SELECT ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered FROM ApexCodeCoverageAggregate WHERE ApexClassOrTrigger.Name LIKE '%PhysicalLocation%' OR ApexClassOrTrigger.Name LIKE '%AccountResolution%' OR ApexClassOrTrigger.Name LIKE '%ALR%' OR ApexClassOrTrigger.Name LIKE '%Domain%' ORDER BY NumLinesUncovered DESC -- Org-wide aggregate (staging: 933 covered / 11,843 uncovered = 7%) SELECT SUM(NumLinesCovered) covered, SUM(NumLinesUncovered) uncovered FROM ApexCodeCoverageAggregate
Post-Go-Live Monitoring
-- Exceptions today SELECT CreatedDate, Message__c FROM Custom_Exception__c WHERE CreatedDate = TODAY ORDER BY CreatedDate DESC -- New PLs created today (should see new ones after Boomi resumes) SELECT COUNT() FROM Physical_Location__c WHERE CreatedDate = TODAY -- New ALRs today SELECT Relationship_Type__c, COUNT(Id) cnt FROM Account_Location_Relationship__c WHERE CreatedDate = TODAY GROUP BY Relationship_Type__c -- Kill switch status SELECT All_Automations__c, Triggers__c, Batch_Jobs__c, Scheduled_Jobs__c, Queueable_Jobs__c FROM Automation_Settings__c
Automation Settings Reference — 22 toggles, master vs user state
Two Automation_Settings__c records exist. Master (org-level) has everything ON. Drew's user-level override has most things OFF — this was intentional during data migration to prevent triggers from interfering with batch loads.
Master Record (Org Default) — All ON
All 17 individual toggles are also ON at master level.
User Record (Drew) — Mostly OFF
| Toggle | State | Why |
|---|---|---|
All_Automations | ON | |
Triggers | ON | |
Batch_Jobs | ON | |
Scheduled_Jobs | OFF | Prevent scheduled jobs from running during Drew's context |
Queueable_Jobs | OFF | Prevent async resolution from interfering with batch loads |
Account_Trigger | OFF | Disable Account trigger during migration |
Domain_Trigger | OFF | Disable Domain trigger during migration |
Domain_Maintenance | OFF | |
Domain_Validation_Batch | OFF | |
Domain_Duplicate_Detection | OFF | |
Domain_Rematch_Batch | OFF | |
Domain_Redirect_Process | OFF | |
Physical_Location_Enrichment | ON | Needed for PL creation batches |
Location_Duplicate_Batch | OFF | |
Billing_Account_Location_Link | ON | Needed for NSBA → PL linking |
Ultimate_Parent_Batch | OFF | |
Account_Merge_Batch | OFF | |
Account_Orphan_Match | OFF | |
Account_Delete_Protection | OFF | Allow account deletion during migration |
NS_Subscription_Location_Inherit | ON | Needed for NSS → PL inheritance |
Address_Validation | ON | |
Zip_Enrichment | ON |
Before Production Go-Live
Drew's user-level overrides should be deleted or set to all ON. In production, the master record should control everything. No user-level overrides unless needed for a specific integration user (e.g., Boomi).
Emergency Kill (Anonymous Apex)
Automation_Settings__c s = Automation_Settings__c.getOrgDefaults(); s.All_Automations__c = false; upsert s;
How Disabled Batches Behave
When a batch's kill switch is FALSE, its start() method returns Database.getQueryLocator('SELECT Id FROM Physical_Location__c WHERE Id = null') — an empty result set. The batch completes immediately with 0 records processed. No exceptions thrown.
Scheduled Jobs — 3 active jobs in staging
Currently Running
| Job | Schedule | Next Fire (UTC) | Last Fire (UTC) |
|---|---|---|---|
| Domain Validation — Daily | Every day at 07:00 UTC (2:00 AM ET) | 2026-02-02 07:00 | 2026-02-01 07:00 |
| Domain Rematch — Weekly | Every Sunday at 08:00 UTC (3:00 AM ET) | 2026-02-08 08:00 | 2026-02-01 08:00 |
| Domain Duplicate Detection — Weekly | Every Sunday at 09:00 UTC (4:00 AM ET) | 2026-02-08 09:00 | 2026-02-01 09:00 |
Jobs That Should Be Scheduled (Not Yet)
| Job | Recommended Schedule | Why |
|---|---|---|
UltimateParentBatchJob |
Daily, 3 AM ET | Recalculates Top_Level_Parent__c. Currently no job — hierarchy gets stale. |
PhysicalLocationEnrichmentBatch |
Nightly, 4 AM ET | Picks up new/changed PLs and runs resolution. Currently manual only. |
AccountHierarchyBatchJob |
Weekly, Sunday 5 AM ET | Rebuilds Account_Hierarchy__c pre-computed table. Currently 0 records. |
LocationStatusService |
Weekly, Sunday 6 AM ET | Updates Location_Status__c based on subscription data. |
Schedule Commands (for production go-live)
// Domain validation — daily 7:00 UTC System.schedule('DomainValidation_Daily', '0 0 7 * * ?', new DomainValidationScheduler()); // Ultimate parent — daily 8:00 UTC System.schedule('UltimateParent_Daily', '0 0 8 * * ?', new UltimateParentBatchJob()); // PL enrichment — nightly 9:00 UTC System.schedule('PLEnrichment_Nightly', '0 0 9 * * ?', new PhysicalLocationEnrichmentBatch()); // Account hierarchy — weekly Sunday 10:00 UTC System.schedule('AccountHierarchy_Weekly', '0 0 10 ? * SUN', new AccountHierarchyBatchJob());
Metadata Inventory
| Component | Count |
|---|---|
| Apex Classes (custom, no namespace) | 257 |
| Apex Triggers (custom, no namespace) | 57 |
| LWC Components (total) | 213 |
| RAR-specific LWCs | 19 |
| Permission Sets (Revenue_*) | 9 + 1 PSG |
| Lightning Pages (RAR) | 18 |
| Scheduled Apex Jobs | 3 |
Rollback Plan — emergency procedures for production
Emergency Kill Switch
Fastest possible response. Disables all RAR automation in under 60 seconds:
// Kill everything Automation_Settings__c s = Automation_Settings__c.getOrgDefaults(); s.All_Automations__c = false; upsert s; // Or via CLI: echo "Automation_Settings__c s = Automation_Settings__c.getOrgDefaults(); \ s.All_Automations__c = false; upsert s;" | sf apex run --target-org RBProduction
Per-Phase Rollback
| Phase | Rollback Procedure | Time |
|---|---|---|
| 10–11 | Kill all automations + deactivate flows + pause Boomi | 15 min |
| 8 | Delete all ALR records: DELETE [SELECT Id FROM Account_Location_Relationship__c] | 1 hr |
| 7 | Reverse reparented ALRs (restore Previous_Account__c) + reset Merge_Status__c + re-run UltimateParentBatchJob | 2–4 hrs |
| 6 | Revert RecordType assignments + null franchise fields | 1 hr |
| 5 | Delete all PLs (cascade-deletes ALR via Master-Detail) + null PL lookups on NSBA, NSS, NSSL, Venue | 2–4 hrs |
| 4 | Delete all Domains + null Merge_Target__c on Accounts | 1 hr |
| 3 | Null Website_Root__c via Data Loader | 1 hr |
| 2 | Reactivate all 12 Account flows to recorded versions | 30 min |
| 1 | Deploy destructiveChanges.xml | 2–4 hrs |
| 0 | Delete GVS + Remote Site. State/Country picklists: IRREVERSIBLE | 15 min |
Full Rollback (4–6 hours)
Execute in reverse order:
All_Automations__c = FALSE(master kill)- Reactivate Account flows (recorded versions)
- Resume Boomi sync
- Delete data:
Physical_Location__c(cascades ALR),Domain__c,Account_Hierarchy__c - Null RAR fields:
Website_Root__c,Brand_Parent__c,Top_Level_Parent__c,Merge_Target__c,Merged_Into__c,Merge_Status__con Account.Physical_Location__con NSBA, NSS, NSSL, Venue. - Deploy
destructiveChanges.xml - Restore Permission Sets if modified
- Verify org is in pre-deployment state
Data Recovery Sources
| Scenario | Recovery |
|---|---|
Deleted Account (if Database.merge used) | Recycle Bin (15 days) or Full Copy Sandbox |
| Corrupted ALR junctions | Delete bad ALRs → re-run PhysicalLocationEnrichmentBatch |
| Wrong Brand assignment | Set Resolution_Needed__c = true on ALR → run resolution queueable, or manual override via admin console |
| Lost ARR attribution | Re-derive from NS Subscriptions: query SUM(ARR__c) grouped by Physical_Location__c → update PLs |
destructiveChanges.xml rollback has never been executed. Before production deployment, test the full rollback procedure in staging. This is P0-5.
Stakeholders — contacts and escalation path
Escalation Path
- Drew Lambert — code/data issues (first responder)
- Kevin Grothe — org admin, flow/config, Boomi issues
- Nick Bolton — business decision authority
- Aron Kuehnemann — executive escalation
Notification Matrix
| Person | T-7 | T-1 | During | Done | T+1 | Weekly |
|---|---|---|---|---|---|---|
| Kevin | Yes | Yes | Real-time | Yes | Yes | Yes |
| Nick | Yes | Yes | On-call | Yes | Yes | Yes |
| Aron | Yes | — | Escalation | Yes | Yes | Monthly |
| Bill | — | — | On-call | — | — | — |
| Sales Team | Yes | Yes | — | Yes | — | — |
Post-Deployment Hypercare
| Week | Milestone | Success Criteria |
|---|---|---|
| 1 | Stability | Zero critical errors. ARR within 5%. All batches completing. |
| 2 | Adoption | Kevin using admin console. Sales using new pages. No tickets. |
| 3 | Quality | Brand validation >85%. Resolution confidence trending up. |
| 4 | Phase 2 Ready | Weeks 1–3 sustained. Nick/Aron sign off. Phase 2 planning begins. |
Revelate Operations
Rockbot Revenue Architecture Redesign
Deployment Runbook · Business Glossary
CONFIDENTIAL