fix(utm): заменить публичную chob на banch (#327)
deploy-preland / deploy zoomstage.online (push) Successful in 42s
deploy-preland / deploy zoomstage.online (push) Successful in 42s
This commit is contained in:
1 parent
08febba368
commit
965eb2e6a5
12 files changed
+58
-33
No files matched your search
@@ -11,7 +11,7 @@ try{
|
||||
$actual=json_decode(file_get_contents($file)); $before=json_decode($raw);
|
||||
foreach(['host','empty','list','map'] as $key)if(serialize($actual->$key)!==serialize($before->$key))throw new RuntimeException('Изменён соседний JSON тип');
|
||||
if(isset($actual->utm->registration,$actual->utm->bchoice))throw new RuntimeException('Остались старые имена');
|
||||
if(json_encode($actual->utm->reg)!=='{"weights":{"1":3,"2":7},"default":"2"}'||json_encode($actual->utm->chob)!=='{"weights":{"2":8,"1":2},"default":"1"}')throw new RuntimeException('Изменён смысл reg/chob');
|
||||
if(json_encode($actual->utm->reg)!=='{"weights":{"1":3,"2":7},"default":"2"}'||json_encode($actual->utm->banch)!=='{"weights":{"2":8,"1":2},"default":"1"}')throw new RuntimeException('Изменён смысл reg/banch');
|
||||
if($actual->utm->theme->default!=='2'||$actual->utm->focus->default!=='1'||serialize($actual->utm->custom)!==serialize($before->utm->custom))throw new RuntimeException('Неверная миграция enum');
|
||||
$first=file_get_contents($file);exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
||||
if($code!==0||file_get_contents($file)!==$first)throw new RuntimeException('Patch не идемпотентен');
|
||||
@@ -31,5 +31,16 @@ try{
|
||||
if($patched!==$expectedTokens)throw new RuntimeException('Изменены байты вне согласованных source ranges');
|
||||
exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
||||
if($code!==0||file_get_contents($file)!==$patched)throw new RuntimeException('Token patch не идемпотентен');
|
||||
$current='{ "other":1.0,"huge":9223372036854775809,"utm": {"chob" : { "weights":{"2":9e+01,"1":-0.0},"default":2 },"nested":{"chob":"keep"}}}';
|
||||
file_put_contents($file,$current);exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
||||
$renamed=str_replace('"chob" :','"banch" :',$current);
|
||||
if($code!==10||file_get_contents($file)!==$renamed)throw new RuntimeException('api#327: миграция chob→banch должна менять только токен имени');
|
||||
exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file),$out,$code);
|
||||
if($code!==0||file_get_contents($file)!==$renamed)throw new RuntimeException('api#327: повторная миграция не должна писать');
|
||||
foreach(['"chob":{"weights":{"1":1},"default":"1"},"banch":{"weights":{"2":1},"default":"2"}', '"bchoice":{"weights":{"a":1},"default":"a"},"chob":{"weights":{"1":1},"default":"1"}'] as $conflicting){
|
||||
$conflict='{"utm":{'.$conflicting.'}}';file_put_contents($file,$conflict);
|
||||
exec(PHP_BINARY.' '.escapeshellarg($script).' '.escapeshellarg($file).' 2>/dev/null',$out,$code);
|
||||
if($code!==2||file_get_contents($file)!==$conflict)throw new RuntimeException('api#327: конфликт aliases должен блокировать patch без записи');
|
||||
}
|
||||
echo "OK: numeric config migration preserves weights/default/foreign JSON types\n";
|
||||
}finally{unlink($file);}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/** api#326: публичные маски выбирают внутренние варианты без открытых alias. */
|
||||
declare(strict_types=1);
|
||||
$_GET = ['indpic'=>'abcd2', 'theme'=>'abcd2x', 'degr'=>'abcd2', 'reg'=>'abcd1', 'chob'=>'abcd1', 'tp'=>'abcd2', 'cons'=>'abcd3', 'focus'=>'abcd2', 'registration'=>'before', 'bchoice'=>'b', 'chb'=>'a', 'utm_source'=>'abcd9same', 'subid'=>'тест + &'];
|
||||
$_GET = ['indpic'=>'abcd2', 'theme'=>'abcd2x', 'degr'=>'abcd2', 'reg'=>'abcd1', 'banch'=>'abcd1', 'tp'=>'abcd2', 'cons'=>'abcd3', 'focus'=>'abcd2', 'registration'=>'before', 'bchoice'=>'b', 'chb'=>'a', 'utm_source'=>'abcd9same', 'subid'=>'тест + &'];
|
||||
$_SERVER['HTTP_HOST']='zoomstage.online';
|
||||
ob_start(); require dirname(__DIR__).'/index.php'; $html=ob_get_clean();
|
||||
$expected=['indpic'=>'2','theme'=>'light','degr'=>'2','registration'=>'before','bchoice'=>'b','tp'=>'2','cons'=>'3','focus'=>'center'];
|
||||
@@ -17,7 +17,7 @@ foreach(['2','rnd','dark','abcdx','abc',[],null,'abcd0'] as $value) {
|
||||
if(prelandResolveUtm(["theme"=>"абвг2"],$config)["digits"]["theme"]!=="2")throw new RuntimeException("Unicode fifth symbol");
|
||||
for($i=0;$i<50;$i++) if(prelandResolveUtm(['indpic'=>'abcd0'],$config)['digits']['indpic']!=='2')throw new RuntimeException('0 нарушил веса');
|
||||
$settings=json_decode(file_get_contents(dirname(__DIR__).'/config.json'),true);
|
||||
$defaults=['indpic'=>'1','theme'=>'1','degr'=>'1','reg'=>'2','chob'=>'2','tp'=>'2','cons'=>'2','focus'=>'1'];
|
||||
$defaults=['indpic'=>'1','theme'=>'1','degr'=>'1','reg'=>'2','banch'=>'2','tp'=>'2','cons'=>'2','focus'=>'1'];
|
||||
foreach(array_keys($defaults) as $key) foreach(['1','rnd','abcdx','abc',[],null,"\xffabcd2"] as $invalid) {
|
||||
$resolved=prelandResolveUtm([$key=>$invalid,'registration'=>'before','bchoice'=>'b','chb'=>'a'],$settings);
|
||||
if($resolved['digits'][$key]!==$defaults[$key])throw new RuntimeException('Открытый/invalid URL изменил '.$key);
|
||||
@@ -29,3 +29,9 @@ $zero=['utm'=>['theme'=>['weights'=>['2'=>0,'1'=>0],'default'=>'1'],'cons'=>['we
|
||||
if(prelandResolveUtm(['theme'=>'abcd0'],$zero)['digits']['theme']!=='2')throw new RuntimeException('Generic zero weights обязаны выбрать первый ключ, как до #326');
|
||||
if(prelandResolveUtm(['cons'=>'abcd0'],$zero)['digits']['cons']!=='2')throw new RuntimeException('Cons zero weights обязаны сохранить special default');
|
||||
echo "OK: numeric public boundary, defaults, weighted0, foreign values\n";
|
||||
foreach (['abcd1','1','b',[]] as $old) {
|
||||
$resolved=prelandResolveUtm(['chob'=>$old,'bchoice'=>'b','chb'=>'a'],$settings);
|
||||
if($resolved['digits']['banch']!=='2'||isset($resolved['context']['chob']))throw new RuntimeException('api#327: внешний chob должен игнорироваться и удаляться');
|
||||
}
|
||||
$oldConfig=['utm'=>['chob'=>['weights'=>['1'=>5,'2'=>0],'default'=>'1']]];
|
||||
if(prelandResolveUtm([],$oldConfig)['digits']['banch']!=='1')throw new RuntimeException('api#327: старый host config обязан работать до миграции');
|
||||
@@ -11,6 +11,7 @@ $_GET = [
|
||||
'utm_source' => 'stage-ad',
|
||||
'subid' => 'click-42',
|
||||
'key' => 'must-not-replace-client-key',
|
||||
'chob' => 'abcd1ignored',
|
||||
];
|
||||
$_SERVER['HTTP_HOST'] = 'zoomstage.online';
|
||||
|
||||
@@ -44,7 +45,7 @@ if ($params !== $expected) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ($redirect_digits !== ['indpic'=>'1','theme'=>'1','degr'=>'1','reg'=>'2','chob'=>'2','tp'=>'2','cons'=>'2','focus'=>'1']) {
|
||||
if ($redirect_digits !== ['indpic'=>'1','theme'=>'1','degr'=>'1','reg'=>'2','banch'=>'2','tp'=>'2','cons'=>'2','focus'=>'1']) {
|
||||
throw new RuntimeException('Type-in обязан сохранить полный resolved numeric snapshot для handoff/recovery.');
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ if (!is_array($config)) {
|
||||
$failures[] = 'Рабочий config.json должен фиксировать явно согласованный focus=face.';
|
||||
}
|
||||
|
||||
foreach (['indpic', 'theme', 'degr', 'reg', 'chob', 'cons', 'tp'] as $key) {
|
||||
foreach (['indpic', 'theme', 'degr', 'reg', 'banch', 'cons', 'tp'] as $key) {
|
||||
$setting = $config['utm'][$key] ?? null;
|
||||
if (!is_array($setting) || !is_array($setting['weights'] ?? null) || !is_string($setting['default'] ?? null)) {
|
||||
$failures[] = "Рабочий config.json должен хранить валидный stage-снимок UTM {$key}.";
|
||||
|
||||
@@ -2,17 +2,19 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const vm = require('node:vm');
|
||||
const source = fs.readFileSync('/app/components/utm-handoff.php','utf8').split("<<<'JS'\n")[1].split('\nJS;')[0];
|
||||
const source = fs.readFileSync('/app/components/utm-handoff.php','utf8').replace(/\r\n/g,'\n').split("<<<'JS'\n")[1].split('\nJS;')[0];
|
||||
const context = {window:{},URLSearchParams,Uint8Array,crypto:require('node:crypto').webcrypto};
|
||||
vm.runInNewContext(source,context);
|
||||
const handoff=context.window.ZoomzillaUtmHandoff;
|
||||
const defaults={indpic:'1',theme:'1',degr:'1',reg:'2',chob:'2',tp:'1',cons:'2',focus:'1'};
|
||||
const selected={indpic:'2',theme:'2',degr:'2',reg:'1',chob:'1',tp:'2',cons:'3',focus:'2'};
|
||||
const defaults={indpic:'1',theme:'1',degr:'1',reg:'2',banch:'2',tp:'1',cons:'2',focus:'1'};
|
||||
const selected={indpic:'2',theme:'2',degr:'2',reg:'1',banch:'1',tp:'2',cons:'3',focus:'2'};
|
||||
const foreign='utm_source=abcd9same&subid=%D1%82%D0%B5%D1%81%D1%82+%2B+%26&id=42&stage=keep';
|
||||
for(const meta of [
|
||||
{redirectUtm:foreign,utmDigits:selected},
|
||||
{redirectUtm:foreign,utmDigits:{...selected,banch:undefined,chob:'1'}},
|
||||
{redirectUtm:foreign+'&indpic=abcd2&theme=абвг2°r=abcd2®=abcd1&chob=abcd1&tp=abcd2&cons=abcd3&focus=abcd2'},
|
||||
{redirectUtm:foreign+'&indpic=2&theme=light°r=2®istration=before&bchoice=b&tp=2&cons=3&focus=center&chb=a'},
|
||||
{redirectUtm:foreign+'&indpic=abcd2&theme=абвг2°r=abcd2®=abcd1&chob=abcd1&tp=abcd2&cons=abcd3&focus=abcd2'}
|
||||
{redirectUtm:foreign+'&indpic=abcd2&theme=абвг2°r=abcd2®=abcd1&banch=abcd1&tp=abcd2&cons=abcd3&focus=abcd2'}
|
||||
]){
|
||||
const before=JSON.stringify(meta);
|
||||
const first=new URLSearchParams(handoff.query(meta,defaults));
|
||||
@@ -27,7 +29,7 @@ for(const meta of [
|
||||
assert.equal(query.get('utm_source'),'abcd9same');
|
||||
assert.equal(query.get('subid'),'тест + &');
|
||||
assert.equal(query.get('id'),'42'); assert.equal(query.get('stage'),'keep');
|
||||
for(const legacy of ['registration','bchoice','chb'])assert.equal(query.has(legacy),false);
|
||||
for(const legacy of ['registration','bchoice','chb','chob'])assert.equal(query.has(legacy),false);
|
||||
}
|
||||
assert.equal(JSON.stringify(meta),before);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user