Przejdź do głównej zawartości

Polityka planowania dla agentów AI wymaga zaakceptowanych plików intent.md, spec.md i plan.md, zanim agent zmieni wrażliwy kod, taki jak auth, billing, migracje czy infrastruktura. Akceptacją jest merge zatwierdzony przez code ownera, a check CI blokuje każdy pull request, który bez niej dotyka chronionych ścieżek. Plan mode pomaga napisać plan, ale nie egzekwuje polityki.

Ta strona jest dla CTO, który odpowiada za pytanie 17 w CTO Scorecard, i dla tech leada, który ma to wdrożyć. Typowa sytuacja: zespół ustalił, że „ryzykowne zmiany zaczynają się od planu”, wszyscy używają Plan mode, a w zeszłym miesiącu agent i tak wypuścił migrację schematu, której planu nikt nie zatwierdził. Inżynier wyszedł z Plan mode po dwóch minutach, a reviewer zobaczył tylko diff.

Q17 · Wzmacnianie organizacji: Czy zmiany wrażliwe wymagają zaakceptowanych artefaktów intent, spec i plan przed wykonaniem?

Odpowiedź za maksymalną liczbę punktów: zaakceptowane intent, spec i plan są wymagane przed uzyskaniem prawa zapisu; hook lub CI weryfikuje artefakty, a nazwany approver kontroluje ryzykowne akcje.

  • Tabelę wyzwalaczy, która rozstrzyga, które zmiany wymagają zaakceptowanego planu, po ścieżce i ryzyku, a nie po liczbie linii
  • Plik polityki, który commitujesz bez zmian i dopasowujesz w jednym review
  • Workflow „najpierw plan” dla Claude Code, Codex i Cursora, który tworzy trzy artefakty
  • Przetestowany skrypt i workflow CI, które odrzucają pull request dotykający chronionych ścieżek bez zaakceptowanych artefaktów
  • Trzy prompty do skopiowania: szkic planu, atak na plan i porównanie końcowego diffu z planem
  • Test kontrolny bramki, który dowodzi, że bramka działa, bez czytania implementacji

Treść artefaktów pochodzi z szablonów łańcucha artefaktów, a sam etap opisuje strona etapu Plan. Ta strona dotyczy wyłącznie organizacyjnej bramki wokół nich.

Wszystkie trzy agenty potrafią planować przed edycją. Żaden nie zapisuje w twoim repozytorium, kto zaakceptował który plan, i każdy pozwala osobie przy klawiaturze przejść do wykonania. Właśnie tę lukę mierzy Q17.

NarzędzieFunkcja „najpierw plan” (sprawdzone 2026-09-26, chyba że zaznaczono)Co egzekwujeCzego nie udowodni
Claude Code 2.1.283Tryb uprawnień plan: odczyt i analiza, edycje zablokowane do zatwierdzenia planu. Wejście przez /plan, Shift+Tab lub claude --permission-mode planBrak edycji plików w sesji planowaniaŻe plan zaakceptował ktoś inny niż właściciel sesji. Od v2.1.283 większość sesji interaktywnych startuje w trybie auto, a nie w Plan mode, chyba że wybierzesz inaczej
Codex CLI 0.157.1/plan w sesji interaktywnej; starszy --sandbox read-only albo profil uprawnień :read-only (beta) dla dowolnego uruchomieniaBrak zapisów w trybie read-onlycodex exec nie ma flagi planu (sprawdzone w codex exec --help, 0.157.1), więc uruchomienia bez nadzoru potrzebują sandboksa lub profilu uprawnień tylko do odczytu oraz bramki, a nie trybu
CursorPlan Mode „tworzy szczegółowe plany implementacji przed napisaniem jakiegokolwiek kodu” (dokumentacja Cursora, sprawdzone 2026-08-28)Planowanie przed kodem w tej rozmowieAkceptacji, tożsamości approvera ani powiązania planu ze scalonym diffem

Dlatego polityka traktuje Plan mode jako narzędzie autorskie, a kontrolę przenosi tam, gdzie agent nie może jej przedefiniować: do gałęzi domyślnej, CODEOWNERS, ochrony gałęzi i wymaganego checka CI. To ten sam podział na radę i władzę, który polityka governance i autonomii stosuje do każdej kontroli agentów.

Wyzwalaczem jest to, co zmiana może zepsuć, a nie jej rozmiar. Trzy linie w sprawdzaniu tokenu są groźniejsze niż 400 linii zmian w tekstach. Zacznij od tej tabeli i przypisz każdemu wierszowi prawdziwe ścieżki w swoim repozytorium.

WyzwalaczPrzykładowe ścieżkiDlaczego plan jest obowiązkowyNazwany approver
Migracja schematu lub danychdb/migrations/Trudna do cofnięcia; liczy się kolejność deployu i backfilluCode owner platformy danych
Uwierzytelnianie, autoryzacja, sesjesrc/auth/Zły default blokuje użytkowników albo wpuszcza niewłaściwychCode owner bezpieczeństwa
Pieniądze: billing, cennik, uprawnienia do planówsrc/billing/Ciche błędy kosztują przychód lub zwrotyCode owner płatności
Infrastruktura, CI i konfiguracja deployuinfra/, .github/Zmienia znaczenie „zielonego” i „wdrożonego” dla każdej innej zmianyCode owner platformy
Publiczne kontrakty APIapi/openapi.yamlIntegracje zewnętrznych klientów przestają działać, a żaden test tu nie zaświeci się na czerwonoWłaściciel API
Przepływy danych wrażliwychpliki, które czytają lub eksportują dane osoboweEkspozycja regulacyjnaWłaściciel prywatności lub bezpieczeństwa

Wszystko spoza tabeli idzie zwykłą ścieżką evidence bundle. Tabela wyznacza też, gdzie zaczyna się klasa ryzyka high: zmiana, która wymaga zaakceptowanego planu, prawie zawsze ma w bundle klasę high.

Prawo zapisu oznacza tu prawo zapisu do main: agent może szkicować zmianę na gałęzi, ale nic, co dotyka chronionej ścieżki, nie trafi do main bez zaakceptowanego planu.

Commituj politykę obok kodu, którym zarządza, żeby każda sesja agenta i każdy reviewer czytali ten sam tekst. Popraw ścieżki i zespoły, a potem scal plik przez to samo review code ownera, które opisuje.

docs/policies/plan-gate.md
# Plan gate policy
Owner: VP Engineering. Reviewed: quarterly. Version: 1.
## Scope
A change needs accepted artifacts when it touches a protected path:
db/migrations/, src/auth/, src/billing/, infra/, .github/, api/openapi.yaml,
scripts/check-plan-gate.sh.
## Accepted artifacts
Each protected change has a directory changes/SLUG/ with intent.md, spec.md
and plan.md (templates: docs/templates/). The artifacts are accepted when a pull
request that adds them is approved by the code owner of the affected area and
merged to main. Main is the only record of acceptance.
## Implementation
The implementation pull request names its directory with a line
"Change-Dir: changes/SLUG" in its description. It must not edit the accepted
artifacts. A material deviation (new file outside plan.md, changed data shape,
changed rollout or rollback) stops the work: amend the plan in its own pull
request first. A Change-Dir serves one implementation pull request, and every
protected path that pull request touches must appear in the file list of plan.md.
## Enforcement
The plan-gate CI check is required on main. Code-owner review is required for
changes/, the protected paths, and the gate itself. Write access means write
access to main: agents may draft on a branch, but nothing that touches a
protected path reaches main without an accepted plan. Agents never hold merge
rights or production credentials.
## Exceptions
Emergency fixes use the audited ruleset bypass, are named in the incident
record, and get a retroactive plan pull request within two business days.
The platform team reports every bypass in the monthly engineering review.

Plik zostaje po angielsku, bo czytają go agenty i narzędzia, a nazwy w nim muszą zgadzać się ze skryptem. Jeśli zespół pracuje po polsku, dodaj polską wersję obok, ale źródłem prawdy zostaw jeden plik.

Bramka ma trzy części: własność w CODEOWNERS, skrypt sprawdzający i wymagany workflow. Dodaj je w jednym pull requeście, scal go i dopiero wtedy oznacz check jako wymagany. Kolejność ma znaczenie, bo poniższy workflow uruchamia kopię skryptu, która już jest na gałęzi domyślnej.

  1. Przypisz właścicieli. Dodaj katalog zmian, każdą chronioną ścieżkę i samą bramkę do .github/CODEOWNERS. Potem włącz Require review from Code Owners w ochronie gałęzi lub rulesecie dla main.

    # .github/CODEOWNERS
    /changes/ @acme/architecture
    /db/migrations/ @acme/data-platform
    /src/auth/ @acme/security
    /src/billing/ @acme/payments
    /infra/ @acme/platform
    /.github/ @acme/platform
    /api/openapi.yaml @acme/api
    /scripts/check-plan-gate.sh @acme/platform

    Zastąp zespoły @acme/... własnymi. Jeśli jedna grupa architektury jest zbyt ogólna dla /changes/, nadawaj katalogom zmian prefiks domeny, na przykład changes/billing-SLUG/, i dodaj /changes/billing-*/ @acme/payments pod linią /changes/. Wzorzec zakończony / obejmuje katalog i wszystko, co jest w nim zagnieżdżone, a w CODEOWNERS wygrywa ostatnia pasująca linia, więc linia domeny musi stać po ogólnej.

  2. Dodaj skrypt sprawdzający. Przepuszcza pull requesty, które nie dotykają chronionej ścieżki. Dla pozostałych wymaga linii Change-Dir:, wymaga, żeby trzy artefakty były już na gałęzi bazowej, i odrzuca ich edycję w tym samym pull requeście.

    #!/usr/bin/env bash
    # scripts/check-plan-gate.sh: fail a PR that changes protected paths without accepted artifacts
    set -euo pipefail
    BASE="origin/${GITHUB_BASE_REF:?run on a pull_request event}"
    PROTECTED='^(db/migrations/|src/auth/|src/billing/|infra/|\.github/|api/openapi\.yaml$|scripts/check-plan-gate\.sh$)'
    changed="$(git diff --name-only "$BASE"...HEAD)"
    hits="$(grep -E "$PROTECTED" <<<"$changed" || true)"
    if [ -z "$hits" ]; then
    echo "plan-gate: no protected paths changed"
    exit 0
    fi
    printf 'plan-gate: protected paths changed:\n%s\n' "$hits"
    dir="$(printf '%s\n' "${PR_BODY:-}" | tr -d '\r' \
    | sed -nE 's#^Change-Dir:[[:space:]]*(changes/[A-Za-z0-9._-]+)/?[[:space:]]*$#\1#p' | head -n1)"
    if [ -z "$dir" ]; then
    echo "::error::Add a line 'Change-Dir: changes/SLUG' to the PR description."
    exit 1
    fi
    for f in intent.md spec.md plan.md; do
    if ! git cat-file -e "$BASE:$dir/$f" 2>/dev/null; then
    echo "::error::$dir/$f is not on $BASE. Merge the plan PR, approved by a code owner, first."
    exit 1
    fi
    done
    if grep -q "^$dir/" <<<"$changed"; then
    echo "::error::This PR edits the accepted artifacts in $dir. Amend them in a separate plan PR."
    exit 1
    fi
    echo "plan-gate: $dir accepted at $(git log -1 --format=%h "$BASE" -- "$dir")"

    Utrzymuj PROTECTED identyczne z zakresem w pliku polityki. Ostatnia linia wypisuje commit, który zaakceptował plan, czyli wersję artefaktów, z którą związany jest pull request.

  3. Dodaj workflow. Uruchamia się ponownie po edycji opisu i wykonuje skrypt z gałęzi bazowej, więc sama edycja scripts/check-plan-gate.sh w pull requeście nie zmienia werdyktu dla tego samego pull requesta. Pull request, który edytuje także workflow, już może go zmienić; opisuje to akapit pod YAML-em.

    .github/workflows/plan-gate.yml
    name: plan-gate
    on:
    pull_request:
    types: [opened, edited, synchronize, reopened]
    permissions:
    contents: read
    jobs:
    plan-gate:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v7
    with:
    fetch-depth: 0
    persist-credentials: false
    - name: Require accepted intent, spec and plan for protected paths
    run: |
    git show "origin/${GITHUB_BASE_REF}:scripts/check-plan-gate.sh" > "$RUNNER_TEMP/check-plan-gate.sh"
    bash "$RUNNER_TEMP/check-plan-gate.sh"
    env:
    PR_BODY: ${{ github.event.pull_request.body }}

    Opis trafia do skryptu przez env, a nie przez interpolację w linii run, więc tekst w opisie pull requesta nie wstrzyknie poleceń powłoki. Skrypt jest najpierw zapisywany do pliku, więc jego brak przerywa krok. Przy przekazaniu potokiem do bash nieudany git show dałby mu pusty strumień i krok by przeszedł, bo gdy krok run nie podaje shell, GitHub uruchamia go bez pipefail.

    Sam plik workflow nie jest chroniony w ten sposób. Przy zdarzeniu pull_request GitHub uruchamia plik workflow z commita scalającego tego pull requesta, więc pull request może tak zmienić plan-gate.yml, żeby pominąć sprawdzenie i nadal świecić na zielono. Przed tym chroni linia /.github/ w CODEOWNERS z kroku 1 razem z Require review from Code Owners: żadna zmiana workflow nie zostanie scalona bez zgody właściciela z zespołu platformy. Bez tej reguły przeglądu bramka ma charakter wyłącznie doradczy.

  4. Ustaw check jako wymagany. Spodziewaj się, że plan-gate padnie na samym pull requeście konfiguracyjnym, bo skryptu nie ma jeszcze na main. Dlatego check nie jest jeszcze wymagany. Od następnego pull requesta świeci na zielono. Po scaleniu pull requesta konfiguracyjnego dodaj plan-gate jako wymagany status check na main. Prawo do merge’a zostaje przy ludziach; agenty otwierają pull requesty, ale nigdy ich nie scalają.

  5. Dziel każdą chronioną zmianę na dwa pull requesty. Pull request planu dodaje changes/SLUG/ i nic więcej, a zatwierdza go code owner. Pull request implementacji startuje po tym merge’u, zawiera Change-Dir: changes/SLUG i opisuje odchylenia od planu.

  6. Uruchom test kontrolny bramki z następnej sekcji, zanim ogłosisz politykę.

Pliki artefaktów i bramka są takie same dla każdego narzędzia. Różni się to, jak utrzymujesz agenta w trybie tylko do odczytu podczas planowania i jak plan trafia do changes/SLUG/.

Uruchom sesję planowania, która nie może edytować plików:

Okno terminala
claude --permission-mode plan

W trwającej sesji użyj /plan albo przełączaj tryby przez Shift+Tab. Wklej prompt planowania poniżej, dopracuj plan, a potem go zatwierdź i poproś Claude Code, żeby zapisał tylko trzy pliki w changes/SLUG/ i otworzył pull request planu. Jeśli w repozytorium przeważa wrażliwa praca, ustaw planowanie jako domyślne: "permissions": { "defaultMode": "plan" } we wspólnym .claude/settings.json. Ustawienia projektu akceptują plan; ignorują auto i bypassPermissions.

Działanie bramki udowadniasz jej własnymi testami, a nie czytaniem kodu agenta. Uruchom te cztery testy raz przy wdrożeniu i ponownie po każdej zmianie zakresu lub workflow:

TestJak go uruchomićOczekiwany wynik
Chroniona zmiana bez planuOtwórz pull request w wersji roboczej (draft), który edytuje jeden plik w src/auth/ i nie ma linii Change-Dir:plan-gate pada z błędem „Add a line”
Plan w tym samym pull requeścieDodaj do tego pull requesta changes/test/ z trzema plikami i linię Change-Dir:Pada: artefaktów nie ma jeszcze na main
Zaakceptowany planUsuń changes/test/ z draftu, scal te trzy pliki w osobnym pull requeście planu zatwierdzonym przez code ownera, potem zrób rebase draftuPrzechodzi i wypisuje commit akceptujący
Plan edytowany w trakcie implementacjiZmień jedną linię w changes/test/plan.md w drafciePada z komunikatem „Amend them in a separate plan PR”

Potem zrób test świeżej sesji w każdym narzędziu, które wspiera twoja organizacja: otwórz nową sesję bez prywatnego kontekstu i zapytaj „What must happen before you edit db/migrations/?”. Poprawna odpowiedź cytuje docs/policies/plan-gate.md. Jeśli nie cytuje, odwołaj się do polityki we wspólnych regułach opisanych na stronie o wspólnych regułach agentów.

Jako bieżący dowód co miesiąc policz z logów CI: pull requesty dotykające chronionych ścieżek, ile przeszło bramkę za pierwszym razem i ile scalono przez bypass. Rosnąca liczba bypassów to wczesny sygnał, że zakres jest za szeroki albo review planów trwa za długo. Sam zapis akceptacji to scalony pull request planu z zatwierdzeniem code ownera przechowywanym przez GitHub.

Kolejka pull requestów planu staje się wąskim gardłem. Code ownerzy, którzy dostają długie plany, przestają je czytać. Naprawa: ogranicz plan.md do jednego ekranu plus listy plików, najpierw uruchom prompt „atak na plan” i dołącz jego tabelę, a w polityce zapisz oczekiwany czas odpowiedzi na review planu.

Zakres jest za szeroki, więc wszystko wymaga planu. Inżynierowie zaczynają pisać puste plany, żeby przejść dalej. Naprawa: usuń każdą ścieżkę, której dziesięć ostatnich zmian nie spowodowało incydentu ani rollbacku, i przenieś ją na zwykłą ścieżkę evidence bundle. Spodziewaj się tarcia na .github/ od pierwszego dnia, bo każda rutynowa edycja workflow, podbicie wersji akcji przez Dependabota lub Renovate i każda edycja CODEOWNERS wymaga wtedy Change-Dir: zawęź ten wpis w PROTECTED do .github/workflows/plan-gate.yml i .github/CODEOWNERS albo kieruj automatyczne podbicia zależności przez mały, stały plan changes/ci-maintenance/.

Plany są zatwierdzone, ale diff odpływa. Bramka dowodzi, że plan istniał, a nie że kod się go trzyma. Spełnia ją też każdy wcześniej zaakceptowany katalog changes/SLUG/, więc nowy ryzykowny pull request może powołać się na stary, niezwiązany plan. Jeden Change-Dir obsługuje jeden pull request implementacji: prompt porównujący diff z planem i reviewer sprawdzają, że każda chroniona ścieżka, której dotyka pull request, jest na liście plików w plan.md. Naprawa: wymagaj sekcji „Plan deviations” z trzeciego promptu w każdym pull requeście implementacji i niech agent review oznacza pliki, których plan nie wymienia.

Ktoś osłabia bramkę. Edycja PROTECTED albo workflow sama jest chronioną zmianą. Kopia skryptu z gałęzi bazowej chroni tylko skrypt: plik workflow uruchamia się z samego pull requesta, więc da się go zmienić tak, żeby przechodził. Naprawa: trzymaj .github/ i skrypt pod code ownerami platformy z włączonym Require review from Code Owners, bo to ta reguła faktycznie blokuje taką edycję, i dalej uruchamiaj skrypt z gałęzi bazowej, tak jak robi to powyższy workflow.

Awaria nie może czekać na plan. Naprawa: użyj audytowanego bypassu rulesetu, wpisz go do zapisu incydentu i scal retroaktywny pull request planu w ciągu dwóch dni, które wyznacza polityka. Przeglądaj każdy bypass co miesiąc.

Ścieżka w monorepo się przenosi. Katalog po zmianie nazwy po cichu wypada z PROTECTED. Naprawa: dodaj test jednostkowy, który sprawdza, że każdy chroniony katalog ze skryptu nadal istnieje w repozytorium.

Plan gate to jedna z kilku kontroli. Umieść ją obok pozostałych, a potem połącz z tym, co reviewerzy czytają przy merge’u.