- agent-handoff-2026-03-10.md — GPT-5.4 code review (lifecycle issues, invocation history gap) - opus-pragmatic-review-2026-03-10.md — Opus прагматичный review для небольшого провайдера - Opus: gVisor/LLM validation — overkill для MVP, фокус на быстрые фиксы + ResourceQuota/NetworkPolicy - Обновлён progress.md с новыми документами - .gitignore — добавлен test.token
602 lines
28 KiB
Markdown
602 lines
28 KiB
Markdown
# Подробный handoff для следующего агента
|
||
|
||
Последнее обновление: 2026-03-10
|
||
|
||
## Назначение документа
|
||
|
||
Этот документ нужен не для презентации проекта, а для практической передачи контекста следующему агенту.
|
||
Цель: после чтения файла должно быть понятно:
|
||
|
||
1. Что в проекте уже сделано и действительно работает.
|
||
2. Где архитектура сильная.
|
||
3. Где есть реальные дефекты, а где просто незавершённые v2-задачи.
|
||
4. Что нужно делать следующим шагом и в каком порядке.
|
||
5. Как проверять изменения с учётом ограничений среды (VPN, возможные TLS timeout).
|
||
|
||
Документ основан на анализе текущего кода, существующей документации и структуры проекта.
|
||
Сетевые E2E-проверки намеренно не делались в рамках этого разбора, потому что среда может шуметь из-за VPN и TLS timeout.
|
||
|
||
---
|
||
|
||
## Краткий вывод
|
||
|
||
Проект находится в хорошем состоянии для рабочего MVP managed serverless platform, но ещё не находится в состоянии production-grade managed cloud service.
|
||
|
||
Что важно понимать сразу:
|
||
|
||
1. Основа выбрана правильно: Kubernetes operator + CRD + build pipeline через S3 + kaniko.
|
||
2. Пользовательский путь уже частично доказан существующими Terraform examples и E2E заметками.
|
||
3. Главные проблемы сейчас не в том, что код "вообще не работает", а в том, что системные свойства платформы пока неполные: event lifecycle, observability, auth/tenancy, строгая валидация контрактов, тестовое покрытие.
|
||
|
||
Итоговая инженерная оценка:
|
||
|
||
1. Как технический фундамент для v1: хорошо.
|
||
2. Как demo/MVP для внутренней обкатки: хорошо.
|
||
3. Как настоящий managed cloud service: пока рано, есть несколько архитектурно значимых дыр.
|
||
|
||
---
|
||
|
||
## Что уже реализовано и выглядит здраво
|
||
|
||
### 1. Правильный control plane фундамент
|
||
|
||
Текущая модель сервиса строится через CRD и operator-подход:
|
||
|
||
1. Function описывает функцию и её runtime/config.
|
||
2. Trigger описывает способ вызова.
|
||
3. FunctionJob описывает одноразовый запуск.
|
||
|
||
Ключевые файлы:
|
||
|
||
1. api/v1alpha1/function_types.go
|
||
2. api/v1alpha1/trigger_types.go
|
||
3. api/v1alpha1/job_types.go
|
||
4. controllers/function_controller.go
|
||
5. controllers/trigger_controller.go
|
||
6. controllers/functionjob_controller.go
|
||
|
||
Это хорошее решение для системы, которая управляет lifecycle k8s-ресурсов, потому что:
|
||
|
||
1. Desired state вынесен в CRD.
|
||
2. Reconcile loop естественно ложится на build/deploy/cleanup.
|
||
3. Kubernetes остаётся источником правды по текущему фактическому состоянию ресурсов.
|
||
|
||
### 2. Build pipeline собран прагматично и без лишней магии
|
||
|
||
Фактически реализована понятная цепочка:
|
||
|
||
1. API принимает zip.
|
||
2. Upload handler генерирует Dockerfile и tar.gz контекст.
|
||
3. Контекст кладётся в S3.
|
||
4. Function controller запускает kaniko Job.
|
||
5. После успешной сборки создаётся/обновляется Deployment функции.
|
||
|
||
Ключевые файлы:
|
||
|
||
1. internal/api/handler/upload.go
|
||
2. internal/builder/builder.go
|
||
3. controllers/function_controller.go
|
||
|
||
Сильные стороны текущего решения:
|
||
|
||
1. Пользователь не думает про Dockerfile.
|
||
2. Сборка отделена от API и не делается внутри процесса оператора.
|
||
3. Используется idempotency guard через аннотацию last-built-s3key.
|
||
4. Используются version-like image refs через hash от S3 key, а не один общий latest для результата сборки.
|
||
|
||
### 3. API и provider уже образуют реальный пользовательский путь
|
||
|
||
Есть не только внутренние CRD, но и внешний контракт:
|
||
|
||
1. REST API на gorilla/mux.
|
||
2. Terraform provider в отдельном модуле.
|
||
3. Набор examples, которые уже реально гонялись.
|
||
|
||
Ключевые файлы:
|
||
|
||
1. internal/api/router.go
|
||
2. internal/api/handler/functions.go
|
||
3. internal/api/handler/triggers.go
|
||
4. internal/api/handler/jobs.go
|
||
5. terraform/provider/...
|
||
6. examples/...
|
||
|
||
Это важно: проект уже живёт не только как "внутренний оператор", а как зачаток полноценного managed продукта.
|
||
|
||
### 4. Видно, что проект уже проходил через реальные эксплуатационные проблемы
|
||
|
||
Это видно по документам:
|
||
|
||
1. doc/errors/log.md
|
||
2. doc/decisions/log.md
|
||
3. doc/progress.md
|
||
|
||
Плюс в том, что проект не застрял на happy path. Уже обнаружены и исправлялись:
|
||
|
||
1. бесконечные build loops,
|
||
2. cleanup после destroy,
|
||
3. cross-namespace проблемы с owner references,
|
||
4. image pull / registry проблемы,
|
||
5. несогласованность Terraform state.
|
||
|
||
Это хороший признак инженерной зрелости даже при сырой архитектуре.
|
||
|
||
---
|
||
|
||
## Текущая фактическая архитектура
|
||
|
||
### 1. Один бинарник совмещает operator manager и REST API
|
||
|
||
Файл: main.go
|
||
|
||
Что происходит:
|
||
|
||
1. Загружается env-конфиг.
|
||
2. Поднимается PostgreSQL store.
|
||
3. Выполняются миграции.
|
||
4. Поднимается S3 client.
|
||
5. Создаётся controller-runtime manager.
|
||
6. Регистрируются Function, Trigger и FunctionJob reconcilers.
|
||
7. Параллельно запускается HTTP API.
|
||
|
||
Это нормальное решение для раннего v1. Оно упрощает деплой и снижает количество moving parts.
|
||
|
||
Ограничение: по мере роста системы API и control plane логика будут мешать друг другу по масштабированию, отказам и ответственности. Но для текущей стадии это приемлемо.
|
||
|
||
### 2. Данные хранятся в двух разных источниках правды
|
||
|
||
Реально сейчас:
|
||
|
||
1. Состояние lifecycle функции и триггеров живёт в Kubernetes CRD/status.
|
||
2. Invocation history задумана в PostgreSQL.
|
||
3. Исходный код и build context живут в S3.
|
||
4. Docker image живёт во внешнем registry.
|
||
|
||
Это нормальная модель, но только если границы между источниками правды строго определены.
|
||
Сейчас эта модель задумана верно, но реализована не до конца, особенно вокруг invocation history.
|
||
|
||
### 3. HTTP вызов функции сейчас устроен через публичный прокси /fn/
|
||
|
||
Ключевые файлы:
|
||
|
||
1. internal/api/router.go
|
||
2. internal/api/handler/invoke.go
|
||
3. controllers/trigger_controller.go
|
||
|
||
Схема:
|
||
|
||
1. Trigger типа http формирует URL вида /fn/{namespace}/{name} через ExternalURL.
|
||
2. API-сервер принимает запрос.
|
||
3. InvokeFunction проксирует его во внутренний Service функции.
|
||
|
||
Для текущего окружения это разумный обход ограничения wildcard DNS.
|
||
|
||
Минус: это превращает API-процесс в data plane proxy для пользовательского трафика. Для MVP годится, для production это создаст узкое место и дополнительные требования к auth, rate limiting, tracing и HA.
|
||
|
||
---
|
||
|
||
## Подтверждённые проблемы и архитектурные долги
|
||
|
||
Ниже перечислены именно подтверждённые проблемы по текущему коду, а не абстрактные придирки.
|
||
|
||
### Критичность A — нужно чинить в ближайших итерациях
|
||
|
||
#### A1. TriggerReconciler рассчитывает на события Function, но реально не подписан на них
|
||
|
||
Файл: controllers/trigger_controller.go
|
||
|
||
Проблема:
|
||
|
||
1. В Reconcile есть ветка: если Function ещё не Ready, Trigger пишет статус waiting и выходит.
|
||
2. Комментарий говорит, что повторный reconcile придёт, когда Function изменится.
|
||
3. Но SetupWithManager регистрирует только For(&Trigger{}), без watch на Function.
|
||
|
||
Следствие:
|
||
|
||
1. Trigger, созданный раньше готовности Function, может застрять в промежуточном состоянии.
|
||
2. Пересчёт будет зависеть не от правильного события, а от случайного следующего изменения Trigger.
|
||
|
||
Почему это важно:
|
||
|
||
Для operator-системы это уже логический дефект event model, а не просто TODO.
|
||
|
||
Что делать:
|
||
|
||
1. Добавить watch на Function.
|
||
2. Обеспечить маппинг Function -> Trigger по namespace + FunctionRef.
|
||
3. Покрыть тестом сценарий "Trigger создан до готовности Function".
|
||
|
||
#### A2. FunctionJobReconciler имеет ту же проблему ожидания готовности Function
|
||
|
||
Файл: controllers/functionjob_controller.go
|
||
|
||
Проблема:
|
||
|
||
1. Если Function не Ready, FunctionJob уходит в Pending и выходит.
|
||
2. В комментарии подразумевается, что reconcile придёт позже.
|
||
3. Но SetupWithManager также подписан только на FunctionJob.
|
||
|
||
Следствие:
|
||
|
||
1. Job может зависнуть в Pending без события-пробуждения.
|
||
2. Фактическое выполнение зависит от внешнего изменения или ручного повторного reconcile.
|
||
|
||
Что делать:
|
||
|
||
1. Добавить watch на Function.
|
||
2. Либо ввести RequeueAfter polling для ожидания Function Ready.
|
||
3. Предпочтительнее watch, если можно аккуратно сматчить зависимости.
|
||
|
||
#### A3. Invocation history заявлена, но фактически не пишется
|
||
|
||
Файлы:
|
||
|
||
1. migrations/001_initial.sql
|
||
2. internal/storage/postgres/store.go
|
||
3. internal/api/handler/invocations.go
|
||
4. internal/api/handler/invoke.go
|
||
|
||
Подтверждённый факт:
|
||
|
||
1. Есть таблица invocations.
|
||
2. Есть SaveInvocation и ListInvocations.
|
||
3. Есть API-эндпоинт чтения истории.
|
||
4. В текущем коде нет места, где SaveInvocation реально вызывается.
|
||
|
||
Следствие:
|
||
|
||
1. API истории вызовов обещает поведение, которого фактически нет.
|
||
2. Документация и UX вводят в заблуждение: кажется, что история есть, но она пустая не потому, что вызовов не было, а потому что они не сохраняются.
|
||
|
||
Что делать:
|
||
|
||
1. Встроить запись инвокации в HTTP proxy path и, отдельно, в FunctionJob execution path.
|
||
2. Определить, что именно считается logs/result/status/duration.
|
||
3. Синхронизировать это решение с API design и examples.
|
||
|
||
#### A4. Multi-tenant модель ещё не реализована, а API уже строится вокруг namespace из URL
|
||
|
||
Файлы:
|
||
|
||
1. internal/api/router.go
|
||
2. internal/api/middleware/auth.go
|
||
3. doc/progress.md
|
||
4. doc/api/design.md
|
||
|
||
Проблема:
|
||
|
||
1. Namespace передаётся пользователем в URL.
|
||
2. Auth пока основан на одном статическом токене.
|
||
3. В документации прямо написано, что настоящая namespace isolation по токену ещё не сделана.
|
||
|
||
Следствие:
|
||
|
||
1. Контракт API пока demo-only.
|
||
2. При переходе к реальному tenant-aware auth почти наверняка придётся менять или сильно прятать namespace от клиента.
|
||
|
||
Что делать:
|
||
|
||
1. Зафиксировать как архитектурное решение: namespace выводится из identity, а не приходит от клиента.
|
||
2. Добавить whoami/identity resolution слой.
|
||
3. Планировать миграцию API аккуратно, пока пользователей мало.
|
||
|
||
### Критичность B — не ломает demo, но делает платформу хрупкой
|
||
|
||
#### B1. Важная часть конфигурации декларативна только на бумаге, но не используется последовательно
|
||
|
||
Файлы:
|
||
|
||
1. internal/config/config.go
|
||
2. main.go
|
||
3. controllers/function_controller.go
|
||
4. controllers/trigger_controller.go
|
||
5. controllers/functionjob_controller.go
|
||
|
||
Проблема:
|
||
|
||
1. Есть FunctionNamespacePrefix в конфиге.
|
||
2. Но контроллеры и wiring жёстко используют sless и sless-fn-.
|
||
|
||
Следствие:
|
||
|
||
1. Конфиг частично ложный: кажется, что поведение настраивается, но реально нет.
|
||
2. Перенос и переиспользование сервиса усложняются.
|
||
|
||
Что делать:
|
||
|
||
1. Либо реально протащить конфиг до всех мест использования.
|
||
2. Либо убрать мнимо-настраиваемое поле, если в v1 это сознательный hardcode.
|
||
|
||
#### B2. TimeoutSec описан в модели, но по сути не обеспечивается runtime-слоем
|
||
|
||
Файлы:
|
||
|
||
1. api/v1alpha1/function_types.go
|
||
2. internal/api/handler/functions.go
|
||
3. runtimes/python3.11/server.py
|
||
4. runtimes/nodejs20/server.js
|
||
|
||
Проблема:
|
||
|
||
1. Поле timeout есть в API/CRD.
|
||
2. Но runtime-обёртка не ограничивает время выполнения функции.
|
||
3. HTTP proxy timeout клиента не равен execution timeout функции как платформенной гарантии.
|
||
|
||
Следствие:
|
||
|
||
1. Контракт платформы частично ложный.
|
||
2. Длительный обработчик может вести себя непредсказуемо с точки зрения пользователя.
|
||
|
||
Что делать:
|
||
|
||
1. Либо честно задокументировать, что timeout пока informational.
|
||
2. Либо реализовать enforcement через runtime/process/k8s job semantics.
|
||
|
||
#### B3. Публичный /fn/ endpoint не отделён от control plane auth модели
|
||
|
||
Файлы:
|
||
|
||
1. internal/api/router.go
|
||
2. internal/api/middleware/auth.go
|
||
3. internal/api/handler/invoke.go
|
||
|
||
Проблема:
|
||
|
||
1. /v1 защищён статическим token.
|
||
2. /fn/ публичен.
|
||
3. Никакой tenant-aware authz на invoke path сейчас нет.
|
||
|
||
Для MVP это допустимо, но следующий агент должен понимать:
|
||
|
||
1. Это не production-ready security model.
|
||
2. Любая работа по auth должна учитывать отдельно control plane и data plane.
|
||
|
||
#### B4. Тестов ядра почти нет
|
||
|
||
Файлы:
|
||
|
||
1. controllers/suite_test.go
|
||
2. остальная кодовая база tests почти отсутствуют
|
||
|
||
Фактическое состояние:
|
||
|
||
1. Есть bootstrap envtest.
|
||
2. Нет содержательных тестов на reconcile lifecycle, cleanup, event propagation, API handler behaviour.
|
||
|
||
Следствие:
|
||
|
||
1. Реальная надёжность сейчас в основном держится на ручных E2E и Terraform examples.
|
||
2. Регрессии в controller logic будут ловиться поздно.
|
||
|
||
### Критичность C — скорее незавершённость и техдолг, чем немедленная поломка
|
||
|
||
#### C1. Статусная модель богаче реальной логики
|
||
|
||
Файлы:
|
||
|
||
1. api/v1alpha1/function_types.go
|
||
2. api/v1alpha1/trigger_types.go
|
||
|
||
Замечание:
|
||
|
||
1. Conditions объявлены, но не ведутся как системная модель статусов.
|
||
2. LastScheduleTime есть, но не видно логики обновления.
|
||
3. PreWarmSeconds есть, но отмечен как нереализованный.
|
||
|
||
Это не срочный баг, но следующий агент не должен тратить время, думая что вся эта модель уже рабочая.
|
||
|
||
#### C2. Cleanup build contexts и registry artefacts не выглядит завершённым
|
||
|
||
Замечание:
|
||
|
||
1. При удалении Function чистятся Deployment/Service/Ingress.
|
||
2. Не видно системного cleanup для S3 contexts и образов registry.
|
||
|
||
Для разработки допустимо.
|
||
Для managed среды это приведёт к накоплению мусора.
|
||
|
||
---
|
||
|
||
## Что не является проблемой само по себе
|
||
|
||
Следующий агент не должен тратить время на преждевременное "улучшательство".
|
||
|
||
### 1. Один бинарник для API и operator — нормально для текущей стадии
|
||
|
||
Не надо сейчас автоматически распиливать на микросервисы.
|
||
Это не даст пропорциональной пользы на текущем этапе.
|
||
|
||
### 2. Выбор gorilla/mux не является узким местом проекта
|
||
|
||
Главные риски проекта не в роутере и не в HTTP фреймворке.
|
||
|
||
### 3. Простые runtime wrappers — нормальны для v1
|
||
|
||
Python/Node runtime обёртки в текущем виде упрощают систему.
|
||
Их ограничения понятны, но они не являются главной ближайшей проблемой по сравнению с event model и invocation persistence.
|
||
|
||
---
|
||
|
||
## Приоритетный план работ для следующего агента
|
||
|
||
Ниже порядок работ, который имеет смысл соблюдать.
|
||
|
||
### Этап 1. Починить lifecycle зависимости Trigger и FunctionJob от Function
|
||
|
||
Цель:
|
||
|
||
1. Trigger и Job не должны зависать, если были созданы до готовности Function.
|
||
|
||
Задачи:
|
||
|
||
1. Добавить watch/mapping из Function в связанные Trigger.
|
||
2. Добавить watch/mapping из Function в связанные FunctionJob или явный polling для ожидания Ready.
|
||
3. Убедиться, что reconcile повторяется по правильным событиям, а не случайно.
|
||
|
||
Файлы-кандидаты:
|
||
|
||
1. controllers/trigger_controller.go
|
||
2. controllers/functionjob_controller.go
|
||
|
||
Критерии готовности:
|
||
|
||
1. Trigger, созданный раньше Function Ready, автоматически становится Active после готовности функции.
|
||
2. FunctionJob, созданный раньше Function Ready, сам продолжает lifecycle без ручного тычка.
|
||
3. Поведение покрыто тестами или хотя бы воспроизводимым локальным сценарием.
|
||
|
||
### Этап 2. Реально включить запись invocation history
|
||
|
||
Цель:
|
||
|
||
1. Сделать так, чтобы API истории вызовов соответствовал реальному поведению платформы.
|
||
|
||
Задачи:
|
||
|
||
1. На HTTP invoke path записывать status, duration, http_status и response/error.
|
||
2. На FunctionJob path записывать результат и статус отдельно как job-triggered invocation либо честно развести две сущности.
|
||
3. Обновить doc/api/design.md и doc/progress.md по факту.
|
||
|
||
Файлы-кандидаты:
|
||
|
||
1. internal/api/handler/invoke.go
|
||
2. internal/storage/postgres/store.go
|
||
3. controllers/functionjob_controller.go
|
||
4. internal/api/handler/invocations.go
|
||
|
||
Критерии готовности:
|
||
|
||
1. После успешного и неуспешного вызова в PostgreSQL появляется запись.
|
||
2. GET invocations возвращает не пустой декоративный список, а реальные записи.
|
||
|
||
### Этап 3. Синхронизировать контракт timeout/status/validation
|
||
|
||
Цель:
|
||
|
||
1. Убрать ложные обещания платформы и несогласованность API.
|
||
|
||
Задачи:
|
||
|
||
1. Решить, что означает TimeoutSec прямо сейчас.
|
||
2. Если не реализуется быстро, явно задокументировать ограничение.
|
||
3. Выправить Create/Update в functions.go и triggers.go так, чтобы значения по умолчанию и validation были последовательными.
|
||
|
||
Файлы-кандидаты:
|
||
|
||
1. internal/api/handler/functions.go
|
||
2. internal/api/handler/triggers.go
|
||
3. api/v1alpha1/function_types.go
|
||
4. doc/api/design.md
|
||
|
||
Критерии готовности:
|
||
|
||
1. API не заставляет клиента задавать поля, которые CRD должен дефолтить.
|
||
2. Update не может случайно испортить spec нулевыми значениями.
|
||
3. Документация не обещает больше, чем реально реализовано.
|
||
|
||
### Этап 4. Уменьшить ложную конфигурируемость
|
||
|
||
Цель:
|
||
|
||
1. Либо сделать конфиг реальным, либо убрать фиктивную настраиваемость.
|
||
|
||
Задачи:
|
||
|
||
1. Разобраться с FunctionNamespacePrefix и хардкодами sless/sless-fn-.
|
||
2. Принять одно из двух решений:
|
||
а) протащить конфиг через контроллеры и main;
|
||
б) удалить поле до тех пор, пока оно реально не нужно.
|
||
|
||
Файлы-кандидаты:
|
||
|
||
1. internal/config/config.go
|
||
2. main.go
|
||
3. controllers/function_controller.go
|
||
4. controllers/trigger_controller.go
|
||
5. controllers/functionjob_controller.go
|
||
|
||
### Этап 5. Добавить минимально полезные автоматические тесты
|
||
|
||
Цель:
|
||
|
||
1. Снизить зависимость от ручных прогонов.
|
||
|
||
Минимальный полезный набор:
|
||
|
||
1. Trigger ждёт Function Ready и потом активируется.
|
||
2. Function deletion чистит дочерние ресурсы.
|
||
3. FunctionJob не зависает в Pending/Running навсегда.
|
||
4. Invoke path корректно пишет invocation history.
|
||
|
||
Важно:
|
||
|
||
Не надо начинать с больших e2e по сети.
|
||
Нужны локальные, детерминированные, дешёвые проверки.
|
||
|
||
---
|
||
|
||
## Как проверять изменения в этой среде
|
||
|
||
С учётом замечания пользователя про VPN и возможные TLS timeout, стратегия проверки должна быть осторожной.
|
||
|
||
### Что предпочитать
|
||
|
||
1. Локальные Go-тесты.
|
||
2. envtest/контроллерные тесты без внешней сети.
|
||
3. Анализ кода и существующих E2E результатов в examples/ и doc/progress.md.
|
||
|
||
### Что не делать первым шагом
|
||
|
||
1. Не начинать с внешних curl/HTTPS smoke test.
|
||
2. Не считать TLS timeout автоматическим подтверждением бага в сервисе.
|
||
3. Не делать выводы по сетевому шуму без локального подтверждения.
|
||
|
||
### Практический порядок проверки
|
||
|
||
1. Сначала локальные unit/envtest проверки.
|
||
2. Потом, если нужно, ограниченные сценарии через provider/examples.
|
||
3. Только в самом конце сетевые end-to-end через ingress.
|
||
|
||
---
|
||
|
||
## Быстрые ориентиры по файлам
|
||
|
||
Если следующему агенту нужно быстро войти в проект, читать в таком порядке:
|
||
|
||
1. main.go
|
||
2. api/v1alpha1/function_types.go
|
||
3. api/v1alpha1/trigger_types.go
|
||
4. api/v1alpha1/job_types.go
|
||
5. controllers/function_controller.go
|
||
6. controllers/trigger_controller.go
|
||
7. controllers/functionjob_controller.go
|
||
8. internal/api/router.go
|
||
9. internal/api/handler/upload.go
|
||
10. internal/api/handler/invoke.go
|
||
11. internal/storage/postgres/store.go
|
||
12. doc/progress.md
|
||
13. doc/errors/log.md
|
||
14. doc/decisions/log.md
|
||
|
||
---
|
||
|
||
## Короткий practical summary для следующего агента
|
||
|
||
Если нужно запомнить только главное:
|
||
|
||
1. Не рефакторить всё подряд. Основа проекта нормальная.
|
||
2. Первые реальные проблемы: event model Trigger/FunctionJob и отсутствие записи invocation history.
|
||
3. Не путать v2-идеи с текущими дефектами: не всё незавершённое надо чинить прямо сейчас.
|
||
4. Не полагаться в первую очередь на внешнюю сеть и TLS smoke test: среда может шуметь.
|
||
5. Любые значимые изменения обязательно фиксировать в doc/progress.md и, при необходимости, в doc/errors/log.md или doc/decisions/log.md.
|
||
|
||
---
|
||
|
||
## Рекомендуемое следующее действие
|
||
|
||
Самый рациональный следующий шаг для нового агента:
|
||
|
||
1. Сфокусироваться на TriggerReconciler и FunctionJobReconciler.
|
||
2. Починить повторное пробуждение от изменений Function.
|
||
3. Добавить под это минимальные локальные тесты.
|
||
|
||
Это даст максимальный выигрыш в надёжности control plane без лишнего расширения функциональности. |