Commit graph

691 commits

Author SHA1 Message Date
4ad309133e Merge pull request 'chore(workflow): diagnostic для stale-claims.yml' (#611) from fix/stale-claims-diagnostic into main
Reviewed-on: #611
2026-05-27 22:03:20 +00:00
lekss361
b86688bc0f chore(workflow): add diagnostic output to stale-claims.yml
Adds runner env + token sanity check + bash -x trace перед запуском cleanup
script. Цель — увидеть actual failure cause в Forgejo Actions logs (manual
runs #1514-1517 все упали ~4s, но script локально работает с тем же PAT).

Diag steps:
- runner environment (python3/curl/mktemp)
- token validity (curl /api/v1/user)
- bash -x для script trace

После merge — trigger manual dispatch + читать logs. Diagnostic строки уберём
fixup-commit'ом после диагноза.

Refs: PR #610 (stale-claims initial), runs #1514-1517 failures.
2026-05-28 01:01:29 +03:00
26559e16e5 Merge pull request 'feat(claude): env-vars refactor + stale-claim cron (Phase 2 final)' (#610) from feat/claude-envvars-and-stale-cron into main
Reviewed-on: #610
2026-05-27 21:40:28 +00:00
lekss361
e4dc866e20 fixup(claude): address review-bot blockers on PR #610
🔴 Critical (3):

1. cleanup-stale-claims.sh: export CUTOFF + STALE_HOURS
   Без `export` Python heredoc child process получал "0" вместо реального
   cutoff → cron всегда видел все issues как fresh → ничего не освобождал.
   Plus added abort при CUTOFF=0 в Python heredoc для defense-in-depth.

2. cleanup-stale-claims.sh: datetime.UTC → datetime.timezone.utc
   datetime.UTC требует Python 3.11+. Forgejo runner ubuntu-latest имеет 3.10.
   datetime.timezone.utc works в 3.8+.

3. cleanup-stale-claims.sh: invert label order — DELETE wip FIRST, потом
   POST ready. Если step 2 (add ready) fails — issue в neutral state без
   status/*, менее опасно чем оба status/ready+status/wip одновременно.

🟠 + 🟡 + 🟢 (5):

4. Added pagination loop (defensive cap 10 pages × 50 = 500 issues), но
   реализована через temp file + Python parsing (не bash JSON concat).

5. Removed dead code: iso_to_epoch() shell helper не использовался.

6. _autonomous_pickup.md: fix broken `Out-Null | if (-not $?)` pattern.
   GetEnvironmentVariable НЕ throws при missing — возвращает $null. $? у
   Get* всегда $true. Заменено на прямую проверку результата.

7. stale-claims.yml: добавлен concurrency group чтобы overlapping runs
   не stomp'ились (хотя 5-min timeout делает overlap unlikely, defensive).

8. Documented updated_at != heartbeat assumption в header script'а.

Не сделано (low/optional):

- Setup script tokens в memory (UX trade-off — не critical)
- Token suffix в console output (минор info leak в shell history)

Refs: PR #610 review by review-bot (sha=297eb29, verdict=changes)
2026-05-28 00:33:27 +03:00
lekss361
297eb29d65 feat(claude): env-vars refactor + stale-claim cron (Phase 2 finalization)
#11: slash-commands и _autonomous_pickup.md теперь читают persistent User-scope
env vars напрямую (FORGEJO_TOKEN_<ROLE>) вместо file-based из ~/.claude/secrets/.

Один раз: scripts/setup-bot-env.ps1 (запускается user'ом локально, кладёт
токены из vault в Windows User registry). После этого окна grab credentials
через [System.Environment]::GetEnvironmentVariable() — никаких файлов.

Все 5 work-as-*.md обновлены (analyst/backend/frontend/reviewer/qa).

#12: stale-claim cleanup — cron каждые 30 минут.

- scripts/cleanup-stale-claims.sh — bash, parses Forgejo API + Python для JSON
- .forgejo/workflows/stale-claims.yml — cron schedule `*/30 * * * *`

Освобождает issues застрявшие в status/wip >4h:
  - assignees=[]
  - +status/ready -status/wip
  - comment "stale claim released, worker likely crashed"

Использует secret FORGEJO_BOT_QA_TOKEN (минимум прав = write:issue).

Setup: secret нужно завести в Forgejo Actions UI после merge —
git.gendsgn.ru/lekss361/gendesign/-/settings/actions/secrets.

Refs: PRs #608, #609. Closes TODO с PR #608 (stale-claim cron).
2026-05-28 00:24:45 +03:00
532b8cdda2 Merge pull request 'feat(claude): Phase 2 — slash-commands + pre-flight + Forgejo labels' (#609) from feat/claude-phase2-labels-commands into main
Reviewed-on: #609
2026-05-27 20:59:33 +00:00
lekss361
018eb1e2ee feat(claude): Phase 2 — slash-commands + pre-flight + Forgejo labels
Phase 2 prep для autonomous multi-window workflow (Phase 1 — PR #608).

Изменения:

1. `.claude/agents/_autonomous_pickup.md` — добавлена Pre-flight checklist:
   - Шаг 1: где взять PAT из vault meta/00_credentials.md
   - Шаг 2: env vars + git identity (GIT_AUTHOR_NAME/EMAIL — критично!)
   - Шаг 3: bot-remote setup (отдельный remote с bot's PAT для audit log)
   - Шаг 4: sanity check identity (curl /user → должен вернуть bot-<role>)

   Без этого commits писались бы под lekss361, не под ботом.

2. `.claude/commands/work-as-*.md` (5 файлов) — slash-commands для запуска окон:
   - work-as-analyst (sonnet, /loop 30m)
   - work-as-backend  (sonnet, /loop dynamic)
   - work-as-frontend (sonnet, /loop dynamic)
   - work-as-reviewer (opus, /loop 5m)
   - work-as-qa       (sonnet, /loop 10m)

   Каждый command:
   - Описывает pre-flight для конкретной роли
   - Ссылается на соответствующий .claude/agents/auto-*.md
   - Перечисляет hard rules для роли
   - Объясняет per-tick workflow

3. Forgejo labels (16 шт, созданы через REST API — не в этом diff):
   scope/{backend,frontend,db,qa,devops}
   status/{ready,wip,review,qa,done,blocked}
   priority/{p0,p1,p2}
   pause-bots, needs-human

Что осталось для активации:

- 5 Forgejo bot-users + PATs (уже созданы 2026-05-27, см. vault)
- ~/.claude/secrets/forgejo-bot-*.token — выгрузка PAT'ов из vault user'ом вручную
- Stale-claim cron (отдельный PR)
- Optional: multi-window launcher через tmux/wezterm

Refs: PR #608 (Phase 1), runbooks/multi_agent_autonomous_workflow.md
2026-05-27 23:50:58 +03:00
29e7e7cdb4 Merge pull request 'feat(claude): auto-* agent stubs для autonomous multi-window workflow (DRAFT)' (#608) from feat/claude-auto-agents-stubs into main
Reviewed-on: #608
2026-05-27 20:27:33 +00:00
lekss361
024bd4c68f merge: forgejo/main into feat/claude-auto-agents-stubs
.gitignore conflict resolved by accepting main's explicit-blacklist approach
(per-path list of .claude/cache, .claude/sessions, etc) — лучше чем мой
.claude/* + whitelist подход, потому что новые .claude/agents/auto-*.md и
.claude/rules/*.md auto-track без необходимости whitelist gymnastics.

Main's структура также удаляет .sentryclirc / sshkey.txt / cian-cookies
mentions — приняты как есть.
2026-05-27 23:20:24 +03:00
lekss361
76784e91fd fixup(claude): address review-bot findings on PR #608
Some checks failed
CI / backend (pull_request) Failing after 43s
CI / frontend (pull_request) Successful in 1m35s
🟠 High:
- auto-backend.md: drop execute_sql из tools (DDL/DML blast radius)
- auto-code-reviewer.md: drop execute_sql + add analyze_query_indexes
- _autonomous_pickup.md: env vars FORGEJO_PAT/BASE_URL → FORGEJO_TOKEN/URL (align с rules/git-pr.md)
- auto-code-reviewer.md: добавлен canonical marker template
  <!-- gendesign-review-bot: sha=X verdict=Y --> + SHA guard перед merge
- auto-code-reviewer.md: self-extending guard exception (NEVER merge PRs
  меняющие git-pr.md auto-merge policy / CLAUDE.md critical rules /
  этот файл / содержащие литеральные secrets)

🟡 Medium:
- _autonomous_pickup.md: STRICT claim race check (length==1 AND assignee==me)
  + best-effort rollback при race lost
- _autonomous_pickup.md: pause-bots mid-work policy (finish current, не abort)
- _autonomous_pickup.md: stale-claim cron explicitly marked TODO
- auto-qa-tester.md: differentiate flaky/prod_down/feature_regression — global
  pause только при prod_down (3× FAIL на /health endpoint), не на flaky
- auto-backend.md: PR body template из rules/git-pr.md (Summary + Test plan + Closes)

🟢 Low:
- _autonomous_pickup.md: BOT_USERNAME documented в env list
- _autonomous_pickup.md: PAT scope guidance (narrow repo, не user-scope)
- auto-analyst.md: de-dup через forgejo_issue frontmatter preferred (fuzzy
  query — fallback)

Refs: PR #608 review by @lekss361 (gendesign-review-bot marker)
2026-05-27 23:11:58 +03:00
lekss361
89303c9769 feat(claude): auto-* agent stubs для autonomous multi-window workflow
Some checks failed
CI / backend (pull_request) Failing after 48s
CI / frontend (pull_request) Successful in 1m39s
DRAFT-файлы для autonomous /loop окон (5 ролей: analyst/backend/frontend/
code-reviewer/qa-tester). НЕ для invoke через Task tool — только как
--append-system-prompt для standalone Claude Code windows с /loop.

Все файлы помечены status:draft. Не активны до сборки .claude/commands/
work-as-* wrappers + Forgejo labels + bot-PATs (см. runbook
multi_agent_autonomous_workflow.md в vault).

Также fix .gitignore: .claude/ → .claude/* чтобы whitelist'ы
!.claude/agents/** работали (git не allow re-include children of ignored
directory).

Refs: runbooks/multi_agent_autonomous_workflow.md (vault)
2026-05-27 22:57:16 +03:00
0380fe9e34 fix(tradein): DaData backfill — Екатеринбург city context (#606 hotfix) (#607)
All checks were successful
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 56s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / deploy (push) Successful in 36s
2026-05-27 14:49:11 +00:00
27fc8101e5 fix(tradein): DaData backfill — Екатеринбург city context (#606 hotfix)
Dry-run на проде показал, что DaData без явного города мапит короткие
street-адреса в Москву по умолчанию («улица Просторная» → «г Москва, ул
Просторная»). Это бы привело к catastrophic false-positive enrichment'у
если бы скрипт запустили без --dry-run.

Two-layer fix:

1. `_with_city_context(addr)` — pre-pends «Екатеринбург, » если в адресе
   ещё нет упоминания города. Идемпотентен, case-insensitive.

2. `_result_in_ekb(result)` — post-filter. Проверяет `raw.city`
   (структурное поле DaData) с fallback на substring search в
   `canonical_address`. Защищает даже если DaData проигнорирует city-префикс
   и всё равно вернёт другой город (например для homonym streets).

`_is_enriched_result()` теперь требует обе проверки: qc_geo IN (0,1)
AND coords AND city == Екатеринбург. Только так делаем UPDATE coords/cadnum.

Без этого fix'а нельзя запускать backfill — все non-EKB false-positives
перезаписали бы NULL coords мусором.

9 новых тестов: city context (prepend / idempotent / case / empty),
post-filter (raw.city / canonical / Moscow reject / None).
Combined 29 passed.
2026-05-27 19:48:37 +05:00
08feb60a7f feat(tradein): DaData /clean/address backfill для houses (PR Q3) (#606)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 47s
Deploy Trade-In / deploy (push) Successful in 35s
2026-05-27 14:43:51 +00:00
e332052d0e feat(tradein): DaData /clean/address backfill для houses (PR Q3)
Migration 070 — добавляет houses.house_fias_id + dadata_qc_geo / qc_house /
enriched_at для tracking. Скрипт scripts/backfill_houses_dadata.py
проходит по ~3.8k rows с NULL coords + ~8.6k с NULL cadnum daily 100/day
(DaData demo quota → ~124 дня walltime для полного прохода).

Per-row SAVEPOINT, resume-safe (фильтр dadata_enriched_at IS NULL),
qc_geo IN (0,1) → overwrite coord-payload, иначе только tracking.
--priority coords|cadnum|both, --dry-run, --limit N (default 100).

20 тестов покрывают happy path qc_geo=0, qc_geo=3 city-level skip,
DaData None response, per-row exception isolation, --dry-run, --limit,
--priority filter, и missing-creds fail-fast.
2026-05-27 19:43:07 +05:00
f438f536b8 feat(tradein): DaData /suggest tier в /suggest endpoint (PR Q2) (#605)
All checks were successful
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 58s
Deploy Trade-In / deploy (push) Successful in 42s
Deploy Trade-In / changes (push) Successful in 5s
2026-05-27 14:09:31 +00:00
386fa8c0e3 feat(tradein): DaData /suggest tier в /suggest endpoint (PR Q2)
Yandex Suggest заблокирован (демо 1k/день исчерпан) — DaData /suggest/address
(10k/день free, token-only auth, лучшее покрытие РФ) заменяет его как Tier 2
после Cadastral FDW. Yandex остаётся как Tier 3 fallback.

- app/services/dadata.py: DadataSuggestion dataclass + async suggest_addresses()
  (token-only, без X-Secret; graceful [] на все ошибки; 5s timeout;
  classifies fias_level→kind: 8=house, 7=street, ≤6=city; count clamp ≤20)
- app/services/geocoder.py: _dadata_suggest() обёртка, дропает entries без
  координат; suggest() теперь Cadastral → DaData → Yandex → Nominatim
- tests/services/test_dadata.py: 15 новых unit-тестов (happy + все error paths)
- tests/services/test_cadastral_reverse.py: +тест DaData до Yandex, update
  fallback теста под новый tier chain

Tests: 62 passed (35 dadata + 20 cadastral reverse + 7 geocode reverse api).
Ruff clean. Reuse DADATA_API_TOKEN from PR Q1 (#604) — secret не нужен для suggest.
2026-05-27 19:08:58 +05:00
0b31431b99 feat(tradein): DaData on-demand enrichment в estimate flow (PR Q1) (#604)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / deploy (push) Successful in 37s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 48s
Closes follow-ups: PR Q2 frontend Suggest swap, PR Q3 NULL-coords backfill, T0_per_house tier matching for Rosreestr deals.

Migration 069 ALTER TABLE adds 6 nullable columns to trade_in_estimates.
ENV: DADATA_API_TOKEN + DADATA_API_SECRET must be set on VPS .env.runtime before requests will be enriched. Without them the service tихо disables and estimator continues as before.

Verified: 20/20 dadata unit tests pass, ruff clean, no regressions in 46 estimator tests. Pre-existing 6 failures in test_estimator_source_quota/test_search_api/test_cian_valuation are unrelated and tracked separately.
2026-05-27 13:56:14 +00:00
a7fa1a4ffa feat(tradein): DaData on-demand enrichment в estimate flow (PR Q1)
Добавляет app/services/dadata.py — async client для DaData /clean/address,
обогащающий target адрес canonical-формой, kadastr_num, ФИАС, координатами
и ближайшим метро. Migration 069 расширяет trade_in_estimates 6 nullable
колонками; estimator.estimate_quality вызывает service после geocode и
сохраняет результат в основной INSERT. AggregatedEstimate отдаёт
canonical_address / house_cadnum / house_fias_id / metro_nearest наружу.

Service graceful: пустые credentials / quota 429 / 5xx / network fail → None,
estimator продолжает работу. Demo tier 100 req/день — хватит для low-traffic
prod и тестов. ENV: DADATA_API_TOKEN, DADATA_API_SECRET.

Tests: 20 unit-тестов через httpx.MockTransport, zero real DaData calls.
Покрыто: happy path, отсутствие creds, короткий адрес, timeout/network,
HTTP 429/401/403/500/502/503, пустой массив, malformed shape, partial
payload, coerce строковых qc-кодов в int, проверка request body+headers.

Закладывает базу для PR Q2 (frontend DaData Suggest, 10k/день free) и
PR Q3 (backfill 339 NULL-coords houses) — обе используют тот же сервис.
2026-05-27 18:50:12 +05:00
b0c03942be feat(tradein): tier badge на DealsCard rows (#603)
All checks were successful
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m38s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / deploy (push) Successful in 38s
2026-05-27 13:15:49 +00:00
99a5a0f73b fix(tradein): Yandex listing_date — keyword + absolute-no-year (#602)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / deploy (push) Successful in 36s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 47s
2026-05-27 13:11:22 +00:00
f5c87201f1 fix(tradein): Avito listing_date extraction (3 формата) (#601)
All checks were successful
Deploy Trade-In / build-backend (push) Successful in 49s
Deploy Trade-In / deploy (push) Successful in 36s
Deploy Trade-In / changes (push) Successful in 1m28s
Deploy Trade-In / build-frontend (push) Has been skipped
2026-05-27 12:55:27 +00:00
64e0d6f4e7 feat(tradein): estimator deals tier (PR M, #564 Phase 3) (#600)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 47s
Deploy Trade-In / deploy (push) Successful in 34s
2026-05-27 12:40:09 +00:00
63756c3c29 feat(tradein): StreetDealsCard с paired listings (PR L, #564 Phase 2) (#599)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Successful in 1m38s
Deploy Trade-In / deploy (push) Successful in 35s
Deploy Trade-In / build-backend (push) Has been skipped
2026-05-27 12:29:06 +00:00
577ddc0654 chore(tradein): drop spurious v_street_sales_vs_listings (#598)
All checks were successful
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 33s
Deploy Trade-In / deploy (push) Successful in 33s
2026-05-27 12:23:18 +00:00
39da0f0644 feat(tradein): sales-vs-listings endpoint (PR K, foundation #564) (#597)
All checks were successful
Deploy Trade-In / changes (push) Successful in 45s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 1m38s
Deploy Trade-In / deploy (push) Successful in 45s
2026-05-27 11:55:44 +00:00
1d8cfb967f feat(tradein): backfill 18k existing listings (PR J) (#596)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 45s
Deploy Trade-In / deploy (push) Successful in 38s
2026-05-27 10:29:40 +00:00
7e24ccbf2c feat(tradein): hook matching в save_listings — fill listing_sources (PR I) (#595)
All checks were successful
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 52s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / deploy (push) Successful in 40s
2026-05-27 10:02:37 +00:00
42ab74e2e8 feat(tradein): MapPicker snap marker — Phase 5 of #582 (#594)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 48s
Deploy Trade-In / build-frontend (push) Successful in 1m44s
Deploy Trade-In / deploy (push) Successful in 39s
2026-05-27 09:30:17 +00:00
aa70e9e155 fix(tradein): yandex_realty captures house number + parse_rub strips NBSP (#593)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 55s
Deploy Trade-In / deploy (push) Successful in 42s
2026-05-27 07:23:36 +00:00
1ce9e10012 feat(tradein): persistent infra для backfill scripts (PR F) (#592)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Successful in 46s
Deploy Trade-In / build-backend (push) Successful in 1m38s
Deploy Trade-In / deploy (push) Successful in 42s
2026-05-27 06:59:54 +00:00
3c506222e6 feat(tradein): Phase 2-3 of #582 — Yandex backfill + canonical audit (#591)
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / build-backend (push) Successful in 23s
Deploy Trade-In / deploy (push) Successful in 36s
Deploy Trade-In / build-frontend (push) Has been skipped
2026-05-27 06:30:54 +00:00
56a7a36c9a feat(auth): UserMenu — личный кабинет top-right (PR D) (#590)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m45s
Deploy Trade-In / deploy (push) Successful in 38s
Deploy / build-frontend (push) Successful in 3m0s
Deploy / deploy (push) Successful in 58s
2026-05-26 10:48:57 +00:00
d954be1331 fix(auth): scripts/auth/*.sh — правильный SNIPPET path (#589) 2026-05-26 08:39:24 +00:00
252bc2de76 chore(security): sync admin hash в users.caddy.snippet (#588)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 29s
Deploy / build-worker (push) Successful in 29s
Deploy / build-frontend (push) Successful in 34s
Deploy / deploy (push) Successful in 56s
2026-05-26 08:29:25 +00:00
c08e4d7811 feat(rbac): pilot scope → только /trade-in/** (#587)
All checks were successful
Deploy Trade-In / changes (push) Successful in 6s
Deploy / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 26s
Deploy / build-backend (push) Successful in 28s
Deploy / build-worker (push) Successful in 28s
Deploy / build-frontend (push) Successful in 27s
Deploy Trade-In / deploy (push) Successful in 36s
Deploy / deploy (push) Successful in 55s
Decision 2026-05-26: pilot не видит landing/analytics/site-finder/concept, только Trade-In.
2026-05-26 07:40:44 +00:00
7a2b055b35 feat(rbac): frontend route-guard + nav filter (#586)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m42s
Deploy Trade-In / deploy (push) Successful in 39s
Deploy / build-frontend (push) Successful in 2m55s
Deploy / deploy (push) Successful in 1m1s
PR B (frontend) to backend RBAC #585. RouteGuard wraps app, NoAccessScreen on 403 from /me, TopNav filtered by role.
2026-05-26 06:51:45 +00:00
88cdfd6adb feat(rbac): role-based access control via X-Authenticated-User middleware (#585)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy / changes (push) Successful in 6s
Deploy Trade-In / build-frontend (push) Successful in 27s
Deploy / build-frontend (push) Successful in 30s
Deploy Trade-In / build-backend (push) Successful in 1m8s
Deploy Trade-In / deploy (push) Successful in 45s
Deploy / build-backend (push) Successful in 2m40s
Deploy / build-worker (push) Successful in 3m20s
Deploy / deploy (push) Successful in 1m16s
Backend RBAC + Caddy header_up. Closes part of #fixes-rbac-pra.
2026-05-26 06:18:40 +00:00
fc12b2c160 Merge pull request 'feat(tradein): Phase 1 of #582 — address mismatch audit (200-house Yandex baseline)' (#583) from feat/tradein-address-audit-phase1 into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 56s
Deploy Trade-In / deploy (push) Successful in 41s
2026-05-26 05:18:56 +00:00
074e55af5f Merge pull request 'fix(tradein): убрать «PRINZIP» wordmark из шапки' (#584) from fix/tradein-hide-prinzip-brand into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m39s
Deploy Trade-In / deploy (push) Successful in 38s
2026-05-25 08:29:30 +00:00
dcf5e32aa1 fix(tradein): убрать «PRINZIP» wordmark из шапки
Оставляем TI-логотип и «Trade-In» рядом. PRINZIP-брендинг скрыт — для
текущего демо/пилота он не нужен. Когда понадобится white-label под
конкретного заказчика, вернём через `brand-name` slot.

Найдено пользователем в шапке gendsgn.ru/trade-in.
2026-05-25 13:28:48 +05:00
02ad9a1f58 feat(tradein): Phase 1 of #582 — address mismatch audit infrastructure
Stratified 200-house Yandex reverse-geocode audit comparing our DB's
(address, lat/lon) pair against what Yandex.Карты returns for those
coordinates. Лежит фундамент данных для Phases 2-5 (canonical = Yandex
per user decision).

What ships:
- Migration 066: address_mismatch_audit table + FDW foreign table
  gendesign_ekb_districts_geom для stratified sampling.
- Sampling SQL: 8 EKB districts × 25 houses = 200.
- Driver scripts/audit_address_mismatch.py с двумя режимами:
  API (если YANDEX_GEOCODER_API_KEY есть) и Playwright (CAPTCHA-aware,
  персистентный контекст). Resumable по --batch.
- Report SQL: p50/p75/p95 distance, top-20 outliers, per-district breakdown.
- 19 unit-тестов: normalize, distance bind, API parser, resume idempotency,
  captcha → status=blocked.

Devops note: после деплоя миграции — выдать tradein_fdw_reader SELECT на
gendesign.public.ekb_districts_geom перед первым запуском audit.

Refs #582 (Phase 1 of 5). Phase 3 backfill заблокирован до Yandex API
key (#402).
2026-05-25 12:50:30 +05:00
33c4c84467 feat(tradein): этаж/этажность optional + best test presets по deal count (#558)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 44s
Deploy Trade-In / build-frontend (push) Successful in 1m53s
Deploy Trade-In / deploy (push) Successful in 44s
2026-05-24 21:44:44 +00:00
8c540ecec6 fix(tradein): extract_street_name handles Nominatim reverse format (#557)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 40s
Deploy Trade-In / deploy (push) Successful in 38s
2026-05-24 21:03:42 +00:00
4d1c409e18 feat(tradein): «По вашей улице» — StreetDealsCard на real ДКП-сделки Росреестра (#556)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m35s
Deploy Trade-In / deploy (push) Successful in 40s
2026-05-24 20:37:29 +00:00
a63e459e25 feat(tradein): GET /street-deals — ДКП-сделки Росреестра по улице target адреса (#555)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 42s
Deploy Trade-In / deploy (push) Successful in 36s
2026-05-24 20:05:48 +00:00
136202dc80 feat(tradein/scripts): local Playwright runners для Cian backfill (bypass server-IP anti-bot) (#553)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / deploy (push) Successful in 32s
2026-05-24 20:00:59 +00:00
16a8239de7 Merge pull request 'feat(tradein): yandex address backfill — street → full address' (#554) from feat/tradein-yandex-address-backfill into main 2026-05-24 19:59:23 +00:00
d2a0257639 feat(tradein-scripts): scrapers + probes + Phase C improvements (#551)
All checks were successful
Deploy Trade-In / changes (push) Successful in 6s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / deploy (push) Successful in 32s
2026-05-24 19:58:38 +00:00
6bbb026cb4 fix(yandex-valuation): off-by-one cell index in _parse_row_cells (#552)
Some checks failed
Deploy Trade-In / build-backend (push) Successful in 40s
Deploy Trade-In / deploy (push) Has been cancelled
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
2026-05-24 19:57:17 +00:00