Skip to main content

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:

  1. Populate family_id on every monitoring_rules row (mig 057). Without a family, AS is not awarded and the universal formula falls back to legacy. Sample query in Brand Programs README.
  2. Decide on bounty_pool_pct — defaults to 0.000 (Weekly Bounty disabled). Set to 0.05 (recommended starting point) once your community comms are ready. Cron pays out Mon 00:00 UTC.
  3. Set notification_channel_id on partners — required for the Weekly Bounty cron to post the winner announcement. Without it, the cron silently no-ops the announcement.
  4. 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 /cooldowns output 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 quality claims drop by more than ~10% across the brand, your tier-0 reward or cap is probably too low; revisit step 2.
  • Check the 🔒 Upcoming Unlocks section in /cooldowns is 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.

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.