This commit is contained in:
Your Name
2026-09-07 10:07:47 +08:00
parent cf3fbdc5ef
commit d5164b7369
388 changed files with 19863 additions and 18720 deletions
+14 -21
View File
@@ -23,16 +23,11 @@ function conversionPrivateMethod(string $name): ReflectionMethod
$buildFanCountRows = conversionPrivateMethod('buildFanCountRows');
$fanRows = $buildFanCountRows->invoke(null, [
['user_id' => 'alice', 'external_userid' => 'live'],
['user_id' => 'alice', 'external_userid' => 'deleted'],
['user_id' => 'alice', 'external_userid' => 'deleted'], // distinct pair only
['user_id' => 'bob', 'external_userid' => 'deleted-only'],
['user_id' => 'carol', 'external_userid' => 'delete-readded'],
], [
['user_id' => 'alice', 'external_userid' => 'live'],
// A candidate pair that survived a delete/re-add cycle remains effective and is not deleted.
['user_id' => 'carol', 'external_userid' => 'delete-readded'],
['user_id' => 'nobody', 'external_userid' => 'not-a-candidate'],
['add_event_id' => 1, 'user_id' => 'alice', 'external_userid' => 'shared-customer', 'is_deleted' => false],
['add_event_id' => 2, 'user_id' => 'alice', 'external_userid' => 'shared-customer', 'is_deleted' => false], // same pair only once
['add_event_id' => 3, 'user_id' => 'alice', 'external_userid' => 'deleted-only', 'is_deleted' => true],
['add_event_id' => 4, 'user_id' => 'bob', 'external_userid' => 'shared-customer', 'is_deleted' => false],
['add_event_id' => 5, 'user_id' => 'carol', 'external_userid' => 'live', 'is_deleted' => false],
]);
$fanRowsByUser = [];
foreach ($fanRows as $row) {
@@ -42,21 +37,17 @@ foreach ($fanRows as $row) {
deletedFansExpect(
($fanRowsByUser['alice']['add_fans_count'] ?? null) === 2
&& ($fanRowsByUser['alice']['deleted_fans_count'] ?? null) === 1,
'All distinct candidate pairs must count as add fans, with deleted fans retained as a subset'
'The same employee/customer pair must count once, while another customer remains a separate pair'
);
deletedFansExpect(
($fanRowsByUser['bob']['add_fans_count'] ?? null) === 1
&& ($fanRowsByUser['bob']['deleted_fans_count'] ?? null) === 1,
'A deleted-only candidate must count once in add fans and once in its deleted subset'
&& ($fanRowsByUser['bob']['deleted_fans_count'] ?? null) === 0,
'The same customer under a different employee must count as a new employee/customer pair'
);
deletedFansExpect(
($fanRowsByUser['carol']['add_fans_count'] ?? null) === 1
&& ($fanRowsByUser['carol']['deleted_fans_count'] ?? null) === 0,
'A delete/re-add pair that remains effective at period end must not count as deleted'
);
deletedFansExpect(
!isset($fanRowsByUser['nobody']),
'Effective rows outside the source-filtered candidate set must not be counted'
'A live add event must not count as deleted'
);
$newEntityRow = conversionPrivateMethod('newEntityRow');
@@ -146,10 +137,12 @@ deletedFansExpect(
'Dual-role merging and virtual department buckets must propagate deleted_fans_count'
);
deletedFansExpect(
str_contains($logicSource, 'applyHistoricalExternalUserChannelFilter')
str_contains($logicSource, 'applyExternalUserEventChannelFilter')
&& str_contains($logicSource, "'e.id'")
&& str_contains($logicSource, "'e.user_id'")
&& str_contains($logicSource, 'surviving_e.event_time >= ?')
&& str_contains($logicSource, 'surviving_del.event_time >= surviving_e.event_time'),
'Deleted pairs must use historical channel attribution and exclude pairs with a surviving re-add'
&& str_contains($logicSource, 'surviving_del.event_time > surviving_e.event_time'),
'Deleted pairs must use event/employee channel snapshots and recognize a surviving re-add'
);
$pageSource = file_get_contents(