лендинг: имя боевого сервера убрано из пользовательской копии
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 58s
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 58s
«Симуляция пробы покрытия на боевой базе (poincare, 30.08.2026)» доезжала до экрана: CITY_COVERAGE_SOURCE собирается в coverage-copy.ts и рендерится в EstimateFlow.tsx:323. На первом экране лендинга строки не видно — она появляется в форме проверки, после выбора города, поэтому grep по отрендеренной главной давал ноль и дефект выглядел несуществующим. Хостнейм посетителю не сообщает ничего: «на боевой базе» несёт весь смысл. Убран из обеих строк-источников (сверка бэктеста и проба покрытия) и из комментария в статьях. Гейт смотрит в ИСХОДНИК, а не в вывод: какой путь рендера показывает строку сегодня, знать не нужно — завтра он будет другим. Список запретов явный, без эвристики «похоже на хостнейм»: она ловила бы domclick.ru и avito.ru в текстах про источники данных. gendsgn.ru в список НЕ входит — это публичный домен B2B, на который лендинг ссылается кнопкой «Для бизнеса». Гейт проверен фальсификацией: возврат хостнейма даёт красное с указанием landing-facts.ts:207, а не пустой список.
This commit is contained in:
parent
56e4de0b35
commit
00f177df03
3 changed files with 93 additions and 3 deletions
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* Инфраструктурные имена не должны попадать в файлы пользовательской копии.
|
||||
*
|
||||
* 30.08.2026 «Симуляция пробы покрытия на боевой базе (poincare, 30.08.2026)»
|
||||
* доехала до экрана: `CITY_COVERAGE_SOURCE` собирается в `coverage-copy.ts` и
|
||||
* рендерится в `EstimateFlow.tsx:323`. На первом экране лендинга её не видно —
|
||||
* она появляется в форме проверки, после выбора города. Поэтому grep по
|
||||
* отрендеренной главной давал ноль, и дефект выглядел несуществующим.
|
||||
*
|
||||
* Отсюда форма гейта: он смотрит в ИСХОДНИК, а не в вывод. Какой именно путь
|
||||
* рендера сегодня показывает строку, знать не нужно — завтра он будет другим,
|
||||
* а хостнейм прода посетителю не сообщает ничего ни на одном из них.
|
||||
*
|
||||
* Скан идёт по всему тексту файла, включая комментарии: комментарий рядом с
|
||||
* копией — заготовка следующей строки копии, и «на боевой базе» в нём ничем
|
||||
* не хуже имени машины.
|
||||
*/
|
||||
import { readdirSync, readFileSync, statSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const ROOT = join(__dirname, "..");
|
||||
|
||||
/**
|
||||
* Имена машин, контейнеров и внутренних хостов. Список ЯВНЫЙ, а не эвристика:
|
||||
* эвристика на «что-то похожее на хостнейм» ловила бы доменные имена в текстах
|
||||
* про источники данных (domclick.ru, avito.ru), которые тут законны.
|
||||
*
|
||||
* `gendsgn.ru` в список НЕ входит намеренно: это публичный домен B2B, на
|
||||
* который лендинг ссылается кнопкой «Для бизнеса» (`B2B_URL` в content.ts).
|
||||
* Запрет на него сломал бы рабочую ссылку — граница проходит по «внутреннее
|
||||
* имя машины» против «адрес, который посетитель и так увидит в браузере».
|
||||
*/
|
||||
const BANNED = [
|
||||
"poincare",
|
||||
"beget",
|
||||
"tradein-postgres",
|
||||
"tradein-backend",
|
||||
"tradein-scraper",
|
||||
"gendesign-postgres",
|
||||
"gendesign-backend",
|
||||
"glitchtip",
|
||||
"forgejo",
|
||||
];
|
||||
|
||||
/** Файлы копии: то, из чего собирается видимый посетителю текст. */
|
||||
function copySources(dir: string, acc: string[] = []): string[] {
|
||||
for (const name of readdirSync(dir)) {
|
||||
if (name === "__tests__" || name === "node_modules") continue;
|
||||
const full = join(dir, name);
|
||||
if (statSync(full).isDirectory()) {
|
||||
copySources(full, acc);
|
||||
} else if (name.endsWith(".ts") || name.endsWith(".tsx")) {
|
||||
acc.push(full);
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
describe("публичная копия не содержит инфраструктурных имён", () => {
|
||||
const files = copySources(ROOT);
|
||||
|
||||
it("файлы копии вообще найдены — иначе гейт зелёный по построению", () => {
|
||||
// Без этой проверки сломанный обход каталога дал бы пустой список и
|
||||
// «нарушений нет» на любом содержимом.
|
||||
expect(files.length).toBeGreaterThan(20);
|
||||
expect(files.some((f) => f.endsWith("landing-facts.ts"))).toBe(true);
|
||||
expect(files.some((f) => f.endsWith("coverage-copy.ts"))).toBe(true);
|
||||
});
|
||||
|
||||
it.each(BANNED)("нигде не встречается «%s»", (needle) => {
|
||||
const hits: string[] = [];
|
||||
for (const file of files) {
|
||||
const text = readFileSync(file, "utf8");
|
||||
text.split("\n").forEach((line, i) => {
|
||||
if (line.toLowerCase().includes(needle)) {
|
||||
hits.push(`${file.slice(ROOT.length + 1)}:${i + 1}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
expect(
|
||||
hits,
|
||||
`«${needle}» — инфраструктурное имя в файле пользовательской копии. ` +
|
||||
`Посетителю оно не сообщает ничего: «на боевой базе» несёт весь смысл. ` +
|
||||
`Строка может не рендериться сегодня и начать рендериться завтра — ` +
|
||||
`так и вышло с CITY_COVERAGE_SOURCE в EstimateFlow.tsx.`,
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* ЧИСЛА ИЗ МАКЕТА СНЯТЫ (29.08.2026). Макет утверждал «по нашим данным,
|
||||
* средний разрыв между первой ценой в объявлении и ценой сделки — 4,1%, а у
|
||||
* провисевших дольше трёх месяцев доходит до 9%», «расхождение с кадастровой
|
||||
* до 40%» и плитки −4,3% / ×2,4 / 83%. Прод-замер (poincare, 29.08.2026)
|
||||
* до 40%» и плитки −4,3% / ×2,4 / 83%. Прод-замер (29.08.2026)
|
||||
* не подтвердил ни одно:
|
||||
*
|
||||
* | макет | что показал замер |
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export interface MeasuredValue {
|
|||
|
||||
/** Общий источник трёх величин ниже — один и тот же прогон сверки. */
|
||||
const BACKTEST_SOURCE =
|
||||
"Ручная сверка на проде (poincare, 29.08.2026): прогноз МЕРЫ против цены ДКП " +
|
||||
"Ручная сверка на боевой базе (29.08.2026): прогноз МЕРЫ против цены ДКП " +
|
||||
"Росреестра по Екатеринбургу, сделки II квартала 2026 года";
|
||||
|
||||
/**
|
||||
|
|
@ -204,7 +204,7 @@ export interface CityCoverageMeasure {
|
|||
}
|
||||
|
||||
export const CITY_COVERAGE_SOURCE =
|
||||
"Симуляция пробы покрытия на боевой базе (poincare, 30.08.2026): случайные адреса " +
|
||||
"Симуляция пробы покрытия на боевой базе (30.08.2026): случайные адреса " +
|
||||
"активных объявлений, для каждого — когорта самой ручки /coverage (радиус 1 км, то же " +
|
||||
"число комнат, площадь ±15 %, свежесть 14 дней, дедуп по источнику и адресу), " +
|
||||
"собственный адрес из когорты исключён";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue