Культура, яку видно в кожному commit

Коли ви через тиждень після merge не знаходите в репозиторії відповіді, чому рішення ухвалили саме так, і відчуваєте, що час пішов намарно, вам хочеться, щоб кожне рішення лишало слід, щоб його можна було пояснити без здогадів і щоб команда працювала як єдина інженерна система, а не як набір окремих людей. Claude Code швидко читає diff і збирає evidence, але допустимість вирішує людина. Звідси ритм: ви просите, Claude пропонує, система перевіряє, людина вирішує. На прикладі PR #842 пройдемо цей шлях від першого запиту до merge і відкритого system follow-up.

Claude CodeАвтоматизаціяЛюдина
досліджує, підсумовує, пропонує звіряє SHA, запускає checks, блокує stale trace визначає допустимість, затверджує, відповідає за результат
Сьогодні пройдемо: рівень 24, "Робота в команді, traceability і AI engineering culture". Працюємо з вигаданим навчальним репозиторієм; customer data, production credentials і live production actions не використовуються.

Командне рішення про merge

Робота починається не з governance-термінів, а із запиту до Claude Code. Агент має відокремити відомі факти від рішень, на які він не має повноважень.

Запит

Перевір поточний PR #842 за Git state і доступними check results.
Поверни current head SHA, changed areas, evidence і рішення,
які ще має ухвалити людина. Не вирішуй за reviewer.

Відповідь Claude Code

head_sha: a17c2e9
changed: HoldReleaseService, authz policy, audit event
evidence: unit 18/18, authz matrix 6/6, lint, typecheck
missing_decision: security owner approval for authz path

Головне в цій відповіді - останній рядок. Агент не написав "готово до merge" і не став оцінювати залишковий ризик: він назвав рішення, якого бракує, і зупинився. Саме такої форми відповіді й варто вимагати - факти окремо, невирішене окремо.

All checks passed не означає merge approved.

Свіжість approval

Owner відповів швидко: о 09:40 security-owner підтвердив рівно той diff, який агент показав хвилину тому. За півгодини автор розширив роль, і цей approval перестав описувати поточний diff.

09:40  a17c2e9  SUPPORT_MANAGER only   security-owner APPROVED
10:12  b8f09d1  adds SUPPORT_AGENT      author pushed after review
10:13  old approval != decision on b8f09d1

Налаштування незалежні й часто вмикаються разом. Dismiss stale працює суворіше: підписи злітають усі разом, і в схвалений PR уже нічого не підмішати. Most recent push м'якше працює з PR, де кілька reviewer: старі approvals лишаються, достатньо одного свіжого - і не від того, хто пушив. Команді з єдиним reviewer це нічого не спрощує, а якщо правку запушить сам reviewer, підтвердити її стане нікому.

Claude може помітити новий diff. Гарантію свіжості дає правило платформи, а не уважність агента.

Reviewer підтверджує diff, а не намір автора і не майбутню гілку.

GO, HOLD чи SPLIT

Зелені checks не змушують обирати між беззастережним merge і повною відмовою. Іноді найкращий результат review - звузити change.

flowchart LR A["Поточний head SHA"] --> B{"Evidence зібрано?"} B -->|ні| H["HOLD"] B -->|так| C{"Owner схвалив цей diff?"} C -->|так| G["GO для названої дії"] C -->|ні| D{"Ризиковий scope можна відокремити?"} D -->|так| S["SPLIT"] D -->|ні| H

Розвилка на схемі йде не за кольором checks, а за двома питаннями: чи зібрано все evidence і чи owner схвалив саме цей diff. HOLD і SPLIT тут рівноправні робочі результати, а не різні ступені невдачі.

Для PR #842 поведінка для support-manager лишається в change, а розширення до SUPPORT_AGENT іде на окремий threat review.

change_id: PR-842
head_sha: b8f09d1
evidence: unit 18/18, authz matrix 7/7, lint, typecheck
owners: security-owner
decision_for: merge
outcome: HOLD (current-head approval missing)
not_approved: production rollout, SUPPORT_AGENT expansion
decision_for: merge; production rollout і розширення ролі лишаються в not_approved.

Перший крок автора

Механізми повернули PR у HOLD, і далі ні policy, ні check не зроблять наступний крок за вас. Ходів тут небагато, і кожен дешевший, поки розмова не пішла в коментарі PR.

# свій diff цілком, перш ніж кликати reviewer
git diff origin/main...HEAD
СитуаціяПерший крок
PR повернули у HOLDназвати те, чого бракує - факт, owner або свіжий approval
пояснити вдається не весь diffрозібрати незрозумілу частину до review, а не на ньому
зміна зачепила sensitive pathсказати про це до merge, а не після
спільний skill дав поганий результатзафіксувати в PR, а не виправити мовчки

Останній рядок виглядає дрібницею, але саме він тримає спільний актив живим: тихо виправлений вивід skill виглядає як успіх і не доходить до owner. Diff, який ви не можете пояснити рядок за рядком, віддавати на review не можна: відповідатимете ви, а не Claude.


Ланцюг traceability

Trace потрібен не заради історії сесії. Він пов'язує запит із поточним diff, доказами і тією людиною, яка ухвалила обмежене рішення.

flowchart LR I["Issue і намір"] --> S["Специфікація завдання"] S --> A["Нотатка про роботу Claude"] A --> D["Diff на head SHA"] D --> T["Checks та evidence"] T --> R["Review від owner"] R --> V["Назване рішення"]

Кожна стрілка на схемі - передача відповідальності, а не запис у лог. Ліворуч завдання, праворуч назване рішення, а всередині diff прив'язаний до конкретного head SHA: саме ця прив'язка згодом дозволить відновити підстави.

Trace будується навколо переходів відповідальності, а не навколо кількості збереженого тексту.


Мінімальний trace

Запис має пережити скорочення і все одно пояснити рішення. Для PR #842 вистачає семи полів:

ПолеДля кейсу
request / AI roleT-1841; implementation і tests
current headb8f09d1
changedservice, authz, audit event
verifiedtests, lint, policy check
human controlplan confirmed; authz owner decides
open riskrole scope widened after review
decisionHOLD for merge; rollout не розглянуто

Хороший trace можна скоротити без втрати рішення. Raw transcript майже завжди втрачає сенс разом із контекстом.


Витяг замість transcript

Прохання "підсумуй сесію" дає гарний переказ. Потрібен інший output: перевірюваний робочий запис для current diff.

Збери AI-assisted workflow note для current diff.
Потрібні: request, AI role, human control, head SHA,
changed, verified, open risk і pending decision.
Не включай prompts, chain-of-thought, secrets і повторюваний tool output.
request: T-1841
ai_role: implementation, tests
human_control: plan confirmed; authz decision not delegated
head_sha: b8f09d1
changed: hold rule, authz role, audit event
verified: unit 18/18, authz matrix 7/7
open_risk: SUPPORT_AGENT added after review
pending_decision: current-head security-owner approval

Різниця між цими двома блоками не в обсязі, а в перевірюваності. Кожне поле витягу звіряється з Git, CI або PR за кілька секунд; рядок зі стенограми звіряти немає з чим. Тому в запиті перелічені потрібні поля, а не сказано "коротше".


Межі audit trail

Більше telemetry не означає більше accountability. Спочатку команда обирає, на яке питання має відповісти запис, і лише потім вмикає збір.

РівеньЩо отримує командаЦіна
base eventssession, event, decisionнизька після налаштування export
tool detailspaths, commands, MCP і skill namesможливі PII і secrets в arguments
raw contentрозмова і повні bodiesокреме сховище чутливих даних

Не плутайте це з особистим журналом сесії. Хук, який дописує ваші промпти у файл репозиторію, - ваш робочий слід: ви його завели, ви його й видалите. Командний audit trail зберігає чужі ідентичності, живе за retention і доступами, і правила в нього суворіші.

Повний transcript збільшує обсяг sensitive data, доступ і вартість incident response. Audit автоматично кращим не стає.

Policy в робочій сесії

Policy корисна, коли за нею можна визначити наступний допустимий крок за хвилину. Claude застосовує правило до diff, але не схвалює власний output.

Прочитай AI_CODING_POLICY.md і current diff PR #842.
Розклади дії за категоріями allowed, review_required, human_only і prohibited.
Для кожної вкажи правило і наступний крок. Не видавай approval.
allowed: update tests and workflow note
review_required: authz path -> security-owner
human_only: approve current diff; merge PR
prohibited: raw customer export; reusable production credential
next: HOLD or SPLIT until current-head approval

Агент розклав дії за зонами і назвав наступний крок, але не поставив жодної галочки: approval лишився в людини. Заразом це перевірка самої policy - ту, яку можна прикласти до конкретного diff за хвилину, читають, а ту, яку треба вичитувати цілком, обходять.


Правило, owner, enforcement

Правило працює лише тоді, коли зрозуміло, хто його змінює, де воно виконується і чим це підтверджується.

RuleOwnerMechanismEvidence
owner для authz pathsecurity-ownerCODEOWNERS, required code owner review, dismiss staleapproval на current head
trace на current headdeveloper-productivity-ownerвласний required check trace-head-checkstatus на PR head SHA
policy доступна агентовіrepository-policy-ownerimport або інструкція в CLAUDE.mdrule і next step в output

Enforcement без пояснення породжує bypass. Пояснення без enforcement лишається порадою.

Тимчасовий виняток зберігає scope, approver і expires_at. Він послаблює механізм, але не скасовує current-head approval.

Skill генерує, CI перевіряє

Той самий запит на workflow note можна запакувати в skill, щоб ним користувався не лише автор: так і з'явився pr-trace. Нижче skill зібрав trace на момент свого запуску: він зафіксував head a17c2e9, а до моменту перевірки в PR уже з'явився push b8f09d1. У trace є властивість, якої немає у звичайного draft - він актуальний рівно до наступного push. Звіряти записаний SHA з фактичним head має не той, хто його записав:

# Claude Code: /pr-trace
head_sha: a17c2e9
pending_decision: security-owner approval

# CI: trace-head-check
recorded head: a17c2e9
current PR head: b8f09d1
status: FAIL - regenerate trace for current head
flowchart LR S["Claude: pr-trace"] --> N["Чернетка trace"] N --> C["CI: trace-head-check"] H["Поточний head PR"] --> C C -->|збіг| G["Required check: успішно"] C -->|розбіжність| F["Required check: помилка"] G --> R["Рішення людини"]

Схема розводить два потоки, які легко переплутати. Згори йде змістовний draft від Claude, знизу - фактичний head PR, а порівнює їх перевірка, яка нічого не вирішує: required status дає CI, а не рядок у SKILL.md. Рішення людини стоїть після зеленого статусу, а не замість нього.


Pilot спільного активу

Demo від автора відповідає на питання "чи працює в мене". Спільний AI-актив має відповісти на інше: чи зможе другий розробник отримати той самий корисний результат без підказок автора.

flowchart LR C["Workflow-кандидат"] --> P["Pilot в одному репозиторії"] P --> U["Запуск другим користувачем"] U --> M["Виміряти промахи й переробки"] M --> D{"Рішення"} D -->|корисний| A["Прийняти з owner"] D -->|можна виправити| F["Виправити й повторити"] D -->|мала цінність| R["Вивести з використання й вимкнути"]

Ключовий вузол на схемі - запуск другим користувачем, а не рішення в кінці. До нього в команди є лише враження автора, після - вимірювані промахи і переробки, за якими вже можна обирати між adopt, fix і retire.

Pilot окремо перевіряє output Claude з pr-trace і здатність trace-head-check ловити stale SHA.

Спільний AI-актив готовий після відтворюваного результату другого користувача, а не після переконливого demo автора.


Inventory і revalidation

Для одного активу inventory вміщується в README. Цінність не в окремій системі, а в тому, щоб команда знала версію, власника, останнє evidence і швидкий disable path.

ПолеПриклад
asset / versionpr-trace@1.3.0 + trace-head-check@0.4.0
ownerdeveloper-productivity-owner
last validationsecond-user pilot on 8 PR fixtures
disable pathmake check non-required; pin previous workflow

Підставою для revalidation стає не сам календар, а зміна межі:

Текст policy може не змінитися, але вона все одно застаріє, якщо змінився asset, для якого збирали evidence.


Стандартна реакція команди

Policy заборонить дію, CI зупинить stale trace, branch rule заблокує merge. Жоден механізм не змусить розробника зрозуміти diff і помітити неправильне продуктове рішення. Тут починається культура.

ПодіяСтандартна реакція команди
Claude створив patchавтор пояснює diff і відповідає за результат
diff несподівано широкийscope зменшується, а не виправдовується швидкістю моделі
tests зеленікоманда називає claim, який вони підтверджують
review знайшов дефекткоманда усуває root cause і додає evidence, якого бракує
docs розходяться з кодомdocs змінюються в тому самому change
збій повторюєтьсязмінюється policy, skill, hook, check або example

Петля покращення workflow

Поточний PR можна повернути в безпечний стан сьогодні. Системне виправлення потребує окремого власника, перевірки і часу, тому Claude готує draft, але не оголошує роботу закритою.

Підготуй draft postmortem для PR #842.
Розділи immediate containment і system follow-up.
Запропонуй owner, verification і stop condition.
Не став done без evidence нового pilot.
СьогодніОкремий follow-up
PR повернувся у HOLDT-1860 виправляє skill і checker
SUPPORT_AGENT винесений у T-1859owner призначений, термін визначений
head c41d72a отримав approvalverification на 8 PR fixtures
GO дозволяє лише mergestatus OPEN до pilot evidence
change: PR-842 @ c41d72a
decision: GO
decision_for: merge
not_approved: production rollout, SUPPORT_AGENT expansion
evidence: checks + current-head approval + trace-head-check
follow_up: T-1860 OPEN, owner and due date assigned
GO для поточного PR не закриває system follow-up. Claude готує зміну, автоматизація перевіряє новий варіант, людина ухвалює його після pilot evidence.