Files
rm-circle-team-router/qa/placement.mjs
T
martbost 07ab4cec79 Members choose how their link places people
Terry asked how a referral of his would be set up as "Direct with
spillover", and whether his team could follow suit. Two settings, on the
member's own dashboard:

  Team rotation — the join goes to the next position IN THEIR OWN TEAM
                  that still needs its 2
  Direct        — every join lands directly under them, as depth

A new position starts on whatever its SPONSOR was using at the moment it
joined, so a team duplicates its leader by default. That is a one-time
copy, not a live link: a sponsor changing their mind later never moves
anyone already in their team, and an explicit choice is never overwritten
from above. The panel says where an inherited setting came from, so nobody
discovers months later that their link was doing something they did not
pick.

Also closed the hole behind Terry's original complaint: a member's
personal link no longer falls through to the COMPANY rotation when their
leg is fully qualified. Team rotation means rotation inside their own
downline and nothing else — handing someone's referral to a position they
have never met was never the intent, and it is what offered Terry's
prospects #148.

The five positions already on directDefaultIds (21, 137, 139, 30, 840)
read as explicit Direct, so nothing changes for them. Everyone else stays
on Team rotation, which is what they have today.

qa/placement.mjs, 17 checks: defaults, choosing, inheritance from the
sponsor, explicit choices surviving a re-run, a sponsor switching not
moving their existing team, and persistence across a restart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 13:54:14 -05:00

61 lines
3.1 KiB
JavaScript

// The placement setting: two states, inherited once from the SPONSOR at join,
// and an explicit choice that nothing above can overwrite.
import { createRequire } from 'node:module';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
const require = createRequire(import.meta.url);
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'rmc-pl-'));
const placement = require('../placement.js');
placement.init({ dataDir: dir });
const ok = [], bad = [];
const t = (n, c, extra) => { (c ? ok : bad).push(n + (c || !extra ? '' : ' -> ' + extra)); };
const cfg = { directDefaultIds: '21,137,139,30,840' };
// defaults
t('an unknown position defaults to team rotation', placement.get(999, cfg).mode === 'team');
t('and is not marked as an explicit choice', placement.get(999, cfg).explicit === false);
t('a position on the admin list reads as direct', placement.get(840, cfg).mode === 'direct');
t('the admin list counts as explicit, so nothing overwrites it', placement.get(840, cfg).explicit === true);
// choosing
placement.set(500, 'direct');
t('a member can choose direct', placement.get(500, cfg).mode === 'direct');
t('their choice is recorded as explicit', placement.get(500, cfg).explicit === true);
placement.set(500, 'team');
t('and can switch back', placement.get(500, cfg).mode === 'team');
t('a nonsense value is refused', !!placement.set(500, 'sideways').error);
// inheritance: one-time copy from the sponsor
placement.inherit(601, 500, cfg); // sponsor 500 is on team
t('joining under a team-rotation sponsor gives team', placement.get(601, cfg).mode === 'team');
placement.inherit(602, 840, cfg); // sponsor 840 is direct
t('joining under a direct sponsor gives direct', placement.get(602, cfg).mode === 'direct');
t('inherited settings are marked NOT explicit', placement.get(602, cfg).explicit === false);
t('and remember which sponsor they came from', placement.get(602, cfg).from === '840');
// the rule that keeps the tree readable
placement.set(602, 'team'); // the member disagrees with their sponsor
placement.inherit(602, 840, cfg); // a later re-run must not undo that
t('an explicit choice is never overwritten from above', placement.get(602, cfg).mode === 'team');
t('and stays marked as their own', placement.get(602, cfg).explicit === true);
// a sponsor changing their mind does NOT move people already placed
placement.set(700, 'team');
placement.inherit(701, 700, cfg);
placement.set(700, 'direct'); // sponsor switches later
t('a sponsor switching later does not move their existing team', placement.get(701, cfg).mode === 'team');
placement.inherit(702, 700, cfg); // but new joins get the new setting
t('but people who join after do get the new setting', placement.get(702, cfg).mode === 'direct');
// survives a restart
const fresh = fs.readFileSync(path.join(dir, 'placement.json'), 'utf8');
t('settings are persisted, not just in memory', fresh.includes('"602"') && fresh.includes('"700"'));
fs.rmSync(dir, { recursive: true, force: true });
console.log('PASS ' + ok.length);
for (const b of bad) console.log('FAIL ' + b);
process.exit(bad.length ? 1 : 0);