Назад
AGENTS.md
# AGENTS.md — правила работы Codex в trajectory-dev ## Сначала прочитать 1. `docs/README.md` — карта двух контуров документации. 2. `docs/CONTEXT_INDEX.md` — какие файлы читать под конкретную задачу. 3. `docs/PROJECT_STATUS.md` — текущее состояние runtime. 4. `docs/SYSTEM_MAP.md` — карта текущей реализации. Не читай все документы подряд без причины. Выбери минимальный релевантный набор по `CONTEXT_INDEX.md`. ## Два контура документов ### Product contour Canonical product docs живут в `docs/**/*.md`. Это ручной контур команды: видение, пользовательская история, философия, маркетинг, позиционирование и steering input. Правила: - читать при планировании, UX/copy/product задачах и стратегической синхронизации; - не редактировать автоматически без явного запроса человека; - не превращать идеи из product contour напрямую в код без перевода через development contour. ### Development contour Canonical development docs живут в `docs/**/*.md`. Это Codex-managed контур: technical strategy, roadmap программирования, domain model, system map, project status, testing, deploy, open questions, tech debt and iteration log. Правила: - обновлять после meaningful execution-run; - держать документы краткими, проверяемыми и полезными следующему Codex; - если product contour изменился, сначала синхронизировать `docs/TECHNICAL_STRATEGY.md` and roadmap/status docs, затем выбирать coding slice. ## Работа с кодом - Репозиторий реализует текущий пользовательский продукт `Восход` внутри системы `Траектория`. - `/dashboard` — canonical protected home host. `/` остаётся public landing для logged-out users. - Первый полезный путь должен работать без Google Calendar и других внешних интеграций. - `events` — canonical operational truth. - `boards` — view/workflow layer над `events`. - `notes` — semantic node type for knowledge core. - State Flow Machine is the user-facing term. Legacy `tutorial_*` names may remain as transitional physical storage/code identifiers until an explicit migration slice. - First SFM home-save path currently reuses `tutorial_*` substrate, creates inspectable AI audit rows, and falls back to raw capture on low confidence instead of silent mutation. - AI must return structured operations/proposals; backend validates and applies. - External actions require explicit user consent, audit and idempotency. - Keep route constants and other shared UI constants in pure client-safe modules. Do not import DB/auth server helpers into client components through shared route/copy modules. ## Проверки Перед финалом выбери релевантные проверки из `docs/TESTING.md`. Базовые команды: ```bash pnpm test pnpm typecheck pnpm lint pnpm build ``` HTTP smoke: ```bash scripts/smoke-public-dev.sh ``` Persistent browser profile: ```bash scripts/open-dev-browser.sh ``` Если меняется пользовательский flow, auth, access, integration or home/conductor behavior, проверь public dev route and document what was tested. Known environment notes: - If direct test imports fail on missing env, use harmless local placeholders for targeted tests, for example `DATABASE_URL=postgresql://test:test@127.0.0.1:5432/test AUTH_SECRET=test-auth-secret AUTH_URL=http://127.0.0.1:3001 AUTH_TRUST_HOST=true`. - `pnpm test` may discover zero tests by default; run relevant targeted test files when the slice depends on them. - Browser smoke depends on local Chrome/Chromium. If unavailable, say so explicitly and cover the route/auth contract with available HTTP or targeted tests. - `scripts/smoke-public-dev.sh` defaults to the dev public origin. For prod smoke, set the base URL explicitly, for example `DEV_PUBLIC_BASE_URL=https://journeyup.ru scripts/smoke-public-dev.sh`, and report the base URL actually tested. Smoke credentials: - Do not invent ad-hoc production DB users or inline seed helpers during promotion. Use an existing documented smoke credential/fixture path only. If the needed prod credential or fixture is absent, stop that gate and report it as the blocker. - Temporary smoke fixtures are acceptable only when the runbook or a repo-owned script documents them, and the report must say what was created and how it was cleaned up. - Before declaring auth/home/protected smoke blocked, check whether the repo already documents the repo-owned path `pnpm smoke:fixture:prepare` -> `DEV_PUBLIC_BASE_URL=<origin> pnpm smoke:auth` -> `pnpm smoke:fixture:cleanup`. If that path exists, use it instead of stopping at anonymous HTTP plus unit tests. - If dev signed-in smoke is blocked only because `SMOKE_OWNER_*` is absent in the current checkout, use the documented dev-only override path (`pnpm smoke:fixture:prepare -- --email ... --password ... --role ... --status ...` plus `SMOKE_USER_*` for `pnpm smoke:auth`) before calling it a blocker, and clean the temporary fixture up after each run. - The repo-owned signed-in fixture path proves access/auth contracts only. Do not treat it as permission to seed production project/note/event or other domain data inline. For domain-data smoke, use a documented repo-owned fixture/write path with cleanup; if prod lacks that path, stop the gate and record the blocker. - If a slice needs hosted proof for a changed protected route or domain-data completion path, prefer adding or reusing a repo-owned fixture/verify command in the repo over building a one-off shell harness. Do not make `.tmp` scripts, `tsx` stdin snippets, ad-hoc `dotenv` wrappers, or temp files outside the repo the canonical release gate for that slice. - Treat repo-owned smoke fixture flows as stateful and strictly sequential. Do not run `prepare`, `pnpm smoke:auth`, `pnpm smoke:knowledge:prepare`, `pnpm smoke:knowledge:verify`, or cleanup commands in parallel for the same fixture user/tree. - For `pnpm smoke:auth`, redirect expectations for root and direct protected routes all use the same script syntax `redirect:/path`: `SMOKE_EXPECT_ROOT_REDIRECT`, `SMOKE_EXPECT_DASHBOARD`, and `SMOKE_EXPECT_SUBSCRIPTION` should not mix bare `/path` with `redirect:/path`. - `pnpm smoke:auth` also checks owner-only operator routes unless overridden. For pending/banned or non-owner runs, set `SMOKE_EXPECT_OPERATOR_RUNTIME` and `SMOKE_EXPECT_OPERATOR_ANALYSIS` explicitly to the intended redirect/403/skip contract instead of treating the default owner assertion as an app regression. - If prod signed-in smoke is blocked on missing `SMOKE_OWNER_*`, do not invent new credentials just to get a green gate unless the task is explicitly credential recovery. Otherwise stop at the blocker; if it is credential recovery, rerun smoke and record the env change in runbook/status docs. - Keep git/release evidence sequential too. Do not run commit with push, do not run multiple prod runbook steps in parallel, and do not classify promotion from overlapping outputs. For release truth, the authoritative order is: commit -> push -> merge/fast-forward -> prod `build` -> `deploy:restart` -> `deploy:save` -> smoke. Upstream-first release checks: - If the task is to finish or promote work from a dirty/diverged local tree, fetch `origin/main` first and compare the exact bounded runtime contract against refreshed upstream before writing code, cutting a release branch, or spending verification gates. - If refreshed `origin/main` or `/root/apps/trajectory-prod` already contains the same runtime behavior, treat the local patch as stale local state: report `no release delta`, do not create duplicate commits/deploys, and update docs only if one concrete new fact appeared. - A scope may be reopened only by a concrete changed-since fact for that same runtime/release contract: upstream advanced on the bounded files, the bounded files changed after the last verdict, a real blocker/gate cleared, or the user explicitly requested re-verification. Dirty worktree noise, unchanged ahead/behind counts, renamed nearby scopes, or "these files are still modified" are not new facts. - If the last authoritative verdict for the same bounded scope is already `no release delta`, do not rerun tests, smoke, deploy, or another docs-sync just to rediscover it. Move to the next unresolved slice or stop with a short blocker note. - When local-vs-upstream evidence is ambiguous because of index/worktree noise, resolve it against a clean checkout/worktree of refreshed `origin/main` before deciding that anything is missing or before running tests/smoke. - If a slice stops at upstream equivalence, keep the report plain and honest: say what minimal evidence you checked, mark tests/smoke/deploy as `not run`, and do not turn the stop into a long no-op template or another memory rotation. - Do not treat redundant verification on an already cooled `no release delta` scope as a new fact. It should not reopen `ACTIVE_TASKS.md`, rotate `ITERATION_LOG.md`, or create another archive entry unless the rerun uncovered a genuinely new blocker or corrected contract. - When you need a clean release checkout, create it from current upstream first, then compare/copy only the bounded files you would actually ship. Decide release eligibility from that candidate tree, not from stale local commit ranges alone. Schema migrations: - If `pnpm db:generate` or `drizzle-kit` opens an interactive rename/conflict prompt, do not guess. Stop the generator, inspect the schema diff/snapshot, and either choose the documented safe path or write a reviewable manual migration. Never let a migration prompt drive a destructive enum/table rename by accident. ## Production promotion Когда bounded slice завершён, проверки зелёные и документы синхронизированы, продвигай изменение в prod по `docs/PROD_RUNBOOK.md`. Rules: - сначала убедись, что dev worktree содержит только ожидаемые изменения; не добавляй в commit чужие/unrelated файлы; - unrelated dirty worktree сам по себе не повод бросать уже реализованный bounded slice: сначала попробуй reviewable isolation через partial staging, отдельный clean worktree от актуального upstream или другой git-safe path, и только потом фиксируй blocker, если release delta всё ещё нельзя отделить; - сделай reviewable git commit в dev repo и отправь его в remote, если remote доступен; - в `/root/apps/trajectory-prod` обновись через `git pull --ff-only`; - затем выполни regular production deploy из `docs/PROD_RUNBOOK.md`: `pnpm install --frozen-lockfile`, `pnpm db:migrate`, `pnpm build`, `pnpm run deploy:restart`, `pnpm run deploy:save`; - после deploy выполни prod smoke из `docs/SMOKE_TESTS.md` / `docs/PROD_RUNBOOK.md` на `https://journeyup.ru`; - только после зелёного prod smoke отмечай релиз как promoted. Если commit/push/deploy невозможен из-за credentials, remote divergence, миграционного риска или красного smoke, остановись, не форси, и явно зафиксируй blocker и последний успешный шаг. Before starting promotion: - do not promote over a red `pnpm typecheck`, red dev smoke, or unrelated dirty worktree that affects the release gate; - если проверяешь release в clean worktree, сначала приведи его в нормальный checkout state: `pnpm install --frozen-lockfile`, нужные generated Next types (например `pnpm exec next typegen`, если red только на `RouteContext` / `PageProps`), и тот же env/bootstrap, который нужен `build`; не объявляй кодовый blocker раньше такого bootstrap; - if `/api/ready` or public dev routes are 5xx/502 while local checks are green, first separate app code from runtime/proxy drift by checking the local app endpoint, PM2 process state, logs, and reverse proxy target. A stale runtime restart is an infra fix, not a reason to invent unrelated code changes. ## Документы после execution-run Обычно обновить: - `docs/PROJECT_STATUS.md` - `docs/SYSTEM_MAP.md` - `docs/OPEN_QUESTIONS.md` - `docs/TECH_DEBT.md` - `docs/ITERATION_LOG.md` Но если execution-run не добавил нового факта и latest memory уже отражает тот же bounded verdict, оставь living docs без изменений. Обычно одного memory-sync pass достаточно на один новый bounded факт. Если executor уже сохранил exact runtime/release truth и следующий Codex не теряет контекст по `PROJECT_STATUS` / `ACTIVE_TASKS` / `TASK_HISTORY`, не создавай отдельный соседний docs-only цикл только ради второго пересказа тех же commit, smoke или roadmap facts. Для shipped или честно blocked slice по умолчанию достаточно: - одного executor evidence trail; - одного curator memory sync; - strategist-pass без файловых правок, если порядок `now / next / later` уже не изменился. Не переписывай long-form shipped ladders в active docs только ради нового commit id, новой даты или более красивой формулировки. Предпочитай обновление stable anchors: `latest promoted runtime`, `latest docs sync`, `live task`, `next step`, `blocker`, `proof branch`, `smoke base URL`. Если executor только подтвердил, что local `HEAD` ahead of promoted baseline или что dirty worktree всё ещё содержит тот же residue, это не новый memory fact само по себе. Не открывай по такому сигналу новый active task и не переписывай `PROJECT_STATUS.md`/`ITERATION_LOG.md`, пока authoritative upstream-first file/contract check не докажет реальный ещё-неклассифицированный bounded delta. Если менялись сущности, статусы или source of truth, обновить `docs/DOMAIN_MODEL.md`. Если менялась стратегия разработки, обновить `docs/TECHNICAL_STRATEGY.md` and `docs/ROADMAP.md`. ## Patch hygiene for docs - For living docs, patch small stable regions under headings instead of replacing long narrative paragraphs wholesale. - If `apply_patch` fails, re-open the exact current lines and retry with a smaller hunk; do not keep applying stale context. - For docs-only curator/strategist passes, verify `git diff --check` or at least inspect the final diff for duplicate headings, stale release facts, and active-task contradictions. - If curator says "no new memory fact", strategist should normally make no file changes. Another tail rotation or archive move alone is not a new fact. - Pre-existing dirty docs or "while I'm here" compaction is not a reason to edit living memory during strategist. Without a new curator fact or a direct contradiction in active docs, leave strategist-owned files unchanged. - If executor or curator already captured the new fact and the roadmap consequence is unchanged, do not require a second docs-only pass just to restate it under different headings. Prefer one precise update over curator-plus-strategist echo cycles. - If a clean-review candidate is already implemented and only lacks the last bounded release gate, prefer finishing that same slice in the next cycle over opening a parallel product lane or strategist detour. - Use `one new fact -> one memory update` as the default. If executor already captured exact release truth and the active-task order is unchanged, curator should update only the minimal canonical docs, and strategist should usually leave files untouched. - If curator already moved the live task to the next bounded slice and there is no new roadmap consequence beyond that move, strategist should normally make no file edits at all. - Keep `local candidate`, `pushed proof`, `accepted line`, and `prod` distinct. Do not promote a clean-review implementation to broad active-memory truth before commit/push/release classification. - Retrospective findings that affect process should usually land in one dedicated note under active docs or roadmap, not by rephrasing the same lesson across every live-memory file. - When a blocker is already precise and next-step-ready, keep the docs anchored on that blocker and the repo-owned fix path. Do not turn it into a larger memory rewrite or a new instruction to rebuild another temporary harness from scratch. - When a later executor closes the same gate on the same accepted-line commit, replace the stale blocker anchor instead of preserving both states as simultaneous live truth. Keep the old state only in `ITERATION_LOG.md` or archive. - If a prod failure is explained by stale build/runtime state rather than missing source code, fix the deployment artifact on the accepted line, record that operational root cause once, and move on. Do not reopen the product lane or demand a second code patch just to restate the same conclusion. ## Next.js <!-- BEGIN:nextjs-agent-rules --> # This is NOT the Next.js you know This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices. <!-- END:nextjs-agent-rules -->
Сохранить