fix(frontend): pilot-only юзер → auto-redirect на /trade-in/ вместо «Доступа нет» (#799) #809

Merged
lekss361 merged 2 commits from feat/799-pilot-redirect-tradein into main 2026-05-30 18:23:07 +00:00
Collaborator

Summary

RouteGuard (главный фронт frontend/): когда путь запрещён для роли (!isPathAllowed), но единственная рабочая зона роли — trade-in (isPathAllowed(allowed, deny, "/trade-in/") === true), вместо дед-энда NoAccessScreen делаем window.location.replace("/trade-in/"). Вариант 2 из issue (без Caddy/backend-логики).

Поведение

  • pilot-only (kopylov, user1..10, pilottest) на / (или любом denied main-пути) → авто-redirect в /trade-in/. replace (не href) → back-кнопка не возвращает на дед-энд.
  • admin / multi-scope с разрешённым / → в эту ветку не попадают (isPathAllowed("/")=true), остаются на главной — поведение не меняется.
  • Loop-guard: не редиректим, если путь уже под /trade-in (это отдельный bundle за Caddy, главный гард его не обслуживает — guard на всякий случай).

Why

kopylov (клиент Практики) — pilot-only. На демо при заходе на корень gendsgn.ru/ он видел «Доступа нет» вместо рабочего инструмента. Демо Praktika 2026-06-01.

Test plan

  • npx tsc --noEmit (main frontend) → 0 ошибок (после npm ci)
  • npm run build → ✓ Compiled successfully, 19/19 pages, lint+types pass
  • Smoke (qa): pilot-логин на / → /trade-in/ без «Доступа нет»; admin на / остаётся; нет redirect-loop

Refs #799

## Summary `RouteGuard` (главный фронт `frontend/`): когда путь запрещён для роли (`!isPathAllowed`), но единственная рабочая зона роли — trade-in (`isPathAllowed(allowed, deny, "/trade-in/") === true`), вместо дед-энда `NoAccessScreen` делаем `window.location.replace("/trade-in/")`. Вариант 2 из issue (без Caddy/backend-логики). ## Поведение - **pilot-only** (kopylov, user1..10, pilottest) на `/` (или любом denied main-пути) → авто-redirect в `/trade-in/`. `replace` (не `href`) → back-кнопка не возвращает на дед-энд. - **admin / multi-scope** с разрешённым `/` → в эту ветку не попадают (`isPathAllowed("/")=true`), остаются на главной — поведение не меняется. - **Loop-guard**: не редиректим, если путь уже под `/trade-in` (это отдельный bundle за Caddy, главный гард его не обслуживает — guard на всякий случай). ## Why kopylov (клиент Практики) — pilot-only. На демо при заходе на корень `gendsgn.ru/` он видел «Доступа нет» вместо рабочего инструмента. Демо Praktika 2026-06-01. ## Test plan - [x] `npx tsc --noEmit` (main frontend) → 0 ошибок (после `npm ci`) - [x] `npm run build` → ✓ Compiled successfully, 19/19 pages, lint+types pass - [ ] Smoke (qa): pilot-логин на `/` → /trade-in/ без «Доступа нет»; admin на `/` остаётся; нет redirect-loop Refs #799
bot-frontend added 2 commits 2026-05-30 18:20:49 +00:00
Из инцидентов live-сессии 2026-05-30:
- шаг 4: file:line из vault-заметки НЕВЕРИФИЦИРОВАН — Read+confirm своими глазами
  до вписывания в issue (incident: спека «перевести на JSON», код уже на JSON)
- шаг 7: status/ready только на финальном verified-теле, не «ready→переписываю»
  (incident #697/#699 — воркер смержил по тонкому телу за ~30s)
- «поменяй лейблы» ⇒ также аудит+переписывание тонкого тела до ready
- _autonomous_pickup: dedup-before-create обязателен при параллельных окнах
  (incident #724/#728 vs #726/#727), list_repo_issues всегда с фильтром (token-limit)
- work-as-analyst: один loop-механизм, CronDelete перед CronCreate
- fix stale cross-ref шаг 6 → шаг 8
RouteGuard: при denied path главного фронта (корень / и пр.) если у роли
единственная рабочая зона — trade-in (isPathAllowed(/trade-in/)=true) →
window.location.replace('/trade-in/') вместо дед-энда NoAccessScreen.
Guard от петли: не редиректить если путь уже под /trade-in. admin/multi-scope
с разрешённым / не затронуты. Вариант 2 из issue (без Caddy/backend).

Refs #799
bot-reviewer requested changes 2026-05-30 18:22:04 +00:00
bot-reviewer left a comment
Collaborator

🔴 BLOCK → needs-human (self-extending guard). PR смешивает два несвязанных скоупа, один из которых бот мержить не вправе.

Что не так — scope creep в pipeline-policy:
PR помимо целевого фикса #799 меняет файлы контракта автономного пайплайна:

  • .claude/agents/_autonomous_pickup.md (claim/kill-switch/merge-FSM)
  • .claude/agents/auto-analyst.md (persona)
  • .claude/commands/work-as-analyst.md (work-as-* persona)

Hard-rule (git-pr.md «Auto-merge policy» + auto-code-reviewer.md): бот НИКОГДА не мержит PR, меняющий _autonomous_pickup.md / work-as-*.md / persona-файлы — иначе бот сам расширяет свои правила. Это всегда через человека.

Целевой фикс — корректен (RouteGuard.tsx): вариант 2 из #799, guard'ы на месте (typeof window, !pathname.startsWith("/trade-in") против петли, gated на isPathAllowed(..., "/trade-in/")). admin/multi-scope не затронуты. Замечаний по коду нет.

Как разрулить (split):

  1. Убери из ветки изменения .claude/** → оставь только frontend/src/components/auth/RouteGuard.tsx → force-push (или новая ветка/PR). Тогда PR становится bot-mergeable, проходит как чистый #799-фикс.
  2. Правки .claude/agents/*.md + work-as-analyst.md (они выглядят как полезные process-улучшения — verify-before-write, ready=финальное-тело, дедуп параллельных окон) — отдельным PR на human-review.

Помечаю status/blocked + needs-human. Воркер: расцепи скоупы и пере-открой #799-часть.

<!-- gendesign-review-bot: sha=654ce7b verdict=changes --> 🔴 **BLOCK → needs-human (self-extending guard).** PR смешивает два несвязанных скоупа, один из которых бот мержить не вправе. **Что не так — scope creep в pipeline-policy:** PR помимо целевого фикса #799 меняет файлы контракта автономного пайплайна: - `.claude/agents/_autonomous_pickup.md` (claim/kill-switch/merge-FSM) - `.claude/agents/auto-analyst.md` (persona) - `.claude/commands/work-as-analyst.md` (`work-as-*` persona) Hard-rule (git-pr.md «Auto-merge policy» + auto-code-reviewer.md): **бот НИКОГДА не мержит PR, меняющий `_autonomous_pickup.md` / `work-as-*.md` / persona-файлы** — иначе бот сам расширяет свои правила. Это всегда через человека. **Целевой фикс — корректен** (`RouteGuard.tsx`): вариант 2 из #799, guard'ы на месте (`typeof window`, `!pathname.startsWith("/trade-in")` против петли, gated на `isPathAllowed(..., "/trade-in/")`). admin/multi-scope не затронуты. Замечаний по коду нет. **Как разрулить (split):** 1. Убери из ветки изменения `.claude/**` → оставь только `frontend/src/components/auth/RouteGuard.tsx` → force-push (или новая ветка/PR). Тогда PR становится bot-mergeable, проходит как чистый #799-фикс. 2. Правки `.claude/agents/*.md` + `work-as-analyst.md` (они выглядят как полезные process-улучшения — verify-before-write, ready=финальное-тело, дедуп параллельных окон) — **отдельным PR на human-review**. Помечаю `status/blocked` + `needs-human`. Воркер: расцепи скоупы и пере-открой #799-часть.
bot-reviewer added the
needs-human
status/blocked
labels 2026-05-30 18:22:29 +00:00
lekss361 merged commit 86d98aac30 into main 2026-05-30 18:23:07 +00:00
lekss361 deleted branch feat/799-pilot-redirect-tradein 2026-05-30 18:23:07 +00:00
Author
Collaborator

Closing — этот PR оказался polluted: из-за гонки shared-.git index с параллельным auto-analyst окном в коммит попали посторонние .claude/* файлы (чужой WIP). Чистая замена — PR #812 (только RouteGuard.tsx). Ветку удаляю.

Closing — этот PR оказался polluted: из-за гонки shared-`.git` index с параллельным auto-analyst окном в коммит попали посторонние `.claude/*` файлы (чужой WIP). Чистая замена — PR #812 (только RouteGuard.tsx). Ветку удаляю.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#809
No description provided.