Migration Notes
Phase 2 + 2.5 update (May 2026): if you're migrating now, plan for the Phase 2 mechanics from the start. After completing the Phase 1 supersession + unlock setup below, do these additional steps:
- Populate
family_idon everymonitoring_rulesrow (mig 057). Without a family, AS is not awarded and the universal formula falls back to legacy. Sample query in Brand Programs README.- Decide on
bounty_pool_pct— defaults to0.000(Weekly Bounty disabled). Set to0.05(recommended starting point) once your community comms are ready. Cron pays out Mon 00:00 UTC.- Set
notification_channel_idonpartners— required for the Weekly Bounty cron to post the winner announcement. Without it, the cron silently no-ops the announcement.- Decide whether to flip
use_universal_formula = true(mig 063). The bot logs[FormulaDelta]for every event so you can compare legacy vs formula values for ~1 week before flipping. Acceptable delta range is ±25% for most events; investigate larger swings before flipping.Full operator runbook:
discord-bot/docs/PHASE-2-DEPLOY-CHECKLIST.md. The migration order below is for the Phase 1 ladder; Phase 2 mechanics are layered on top.
If your brand has an existing single-tier program (one row per event, generous caps, simple strictness) and you want to migrate onto the Phase 1 supersession + unlock structure, follow this order. The goal is to do it without breaking your members' progression and with a clean rollback path at every step.
1. Snapshot your current rules
Before changing anything, snapshot your current monitoring_rules rows for this brand to a backup table. Keep the snapshot indefinitely — it is your rollback material.
-- Replace the brand_id and the date suffix to match your migration.
CREATE TABLE IF NOT EXISTS monitoring_rules_backup_<brand_short>_<YYYY_MM_DD> AS
SELECT * FROM monitoring_rules
WHERE brand_id = '0xYOURPARTNERADDRESS'
OR server_id IN ('YOUR_SERVER_ID_1', 'YOUR_SERVER_ID_2');
Verify the snapshot row count matches what you expect for your brand.
2. Insert new tier rows alongside existing rules
Do NOT delete or deactivate the existing rules yet. Insert the new tier rows with min_tune_level >= 0 so they coexist. The event-handler's supersession query will not yet have a min_tune_level column to filter on (that arrives in step 3) — until then, the new tier rows are dormant and harmless because the existing single-tier rule still wins by ordering.
If you are using the template.yml skeleton, fill in your brand_id, edit the reward and cap values for any event you want to differ from Resonance Official, then convert each tier and unlock row into a monitoring_rules INSERT. The Resonance Official seed file (workers/sql/migrations/038b_resonance_official_seed.sql) is the worked example.
For each new event, your tier 0 row should match (or only modestly differ from) your existing single-tier rule's reward and cap — this preserves L0 members' earnings during the migration.
3. Mark existing rules inactive (not deleted)
Once your tier rows are in place and verified, soft-deactivate the legacy single-tier rules. Keep them in the database with active = false and an archived_at timestamp in rule_metadata so you can re-enable them if needed.
UPDATE monitoring_rules
SET active = false,
rule_metadata = jsonb_set(
COALESCE(rule_metadata, '{}'::jsonb),
'{archived_at}',
to_jsonb(NOW())
)
WHERE id IN (SELECT id FROM monitoring_rules_backup_<brand_short>_<YYYY_MM_DD>)
AND min_tune_level = 0 -- only legacy single-tier rows
AND active = true;
The min_tune_level = 0 filter ensures you don't accidentally deactivate any tier-0 rows you just inserted in step 2 — those have min_tune_level = 0 too, but they are not in the backup snapshot. Verify by row-count: the backup table size should equal the rows just deactivated.
4. Deploy and observe for 7 days
Roll out the change to production and let it run for a full week. During this period:
- Monitor
/cooldownsoutput for any members reporting unexpected event drop-offs. - Watch the per-event claim rate dashboards — the new tier-0 events should pay out at roughly the same volume as the legacy rules they replaced. If
qualityclaims drop by more than ~10% across the brand, your tier-0 reward or cap is probably too low; revisit step 2. - Check the
🔒 Upcoming Unlockssection in/cooldownsis populated for low-tune members (gives them visible motivation). - Spot-check a few high-tune members (L40+) to confirm they're seeing higher-tier rewards.
Most issues surface within the first 48 hours. After 7 days of stability, the migration is considered final.
5. Rollback procedure
If something is wrong and you need to revert before the 7-day observation period ends, the rollback is symmetric:
-- 1. Reactivate the legacy single-tier rules.
UPDATE monitoring_rules
SET active = true,
rule_metadata = rule_metadata - 'archived_at'
WHERE id IN (SELECT id FROM monitoring_rules_backup_<brand_short>_<YYYY_MM_DD>)
AND active = false;
-- 2. Deactivate the new tier and unlock rows.
UPDATE monitoring_rules
SET active = false
WHERE brand_id = '0xYOURPARTNERADDRESS'
AND id NOT IN (SELECT id FROM monitoring_rules_backup_<brand_short>_<YYYY_MM_DD>);
After rollback, the snapshot table and the now-deactivated tier rows remain in the database as soft-deleted history. If you fix the underlying issue and want to retry the migration, you can simply re-run steps 3 (deactivate the legacy rules again) without re-inserting the tier rows — they're still there, just deactivated.
Notes on related effect-activation migrations
If your brand was previously using tune_charge_multiplier (the old per-claim cap multiplier from Tune-In) — note that the Phase 1 rebalance retired this from the Tune-In write path. Existing rows from source_brand_id = 'resonance_system' were one-shot deactivated in migration 038_tune_rebalance.sql. Charge-Pack perks that grant tune_charge_multiplier were left untouched.
If your brand uses tune_gen_multiplier activations, the same migration also one-shot bumped existing tune-sourced multipliers by 20% to match the new generateLevels() formula. This is a one-time correction; re-running the migration would double-bump, so the migration includes a guard comment noting this.
These two effect-activation migrations are separate from the rule migration above and apply at the platform level, not per-brand. You don't need to do anything special for them in your brand's migration.