Культура, яку видно в кожному commit
Коли ви через тиждень після merge не знаходите в репозиторії відповіді, чому рішення ухвалили саме так, і відчуваєте, що час пішов намарно, вам хочеться, щоб кожне рішення лишало слід, щоб його можна було пояснити без здогадів і щоб команда працювала як єдина інженерна система, а не як набір окремих людей. Claude Code швидко читає diff і збирає evidence, але допустимість вирішує людина. Звідси ритм: ви просите, Claude пропонує, система перевіряє, людина вирішує. На прикладі PR #842 пройдемо цей шлях від першого запиту до merge і відкритого system follow-up.
- зберемо trace для поточного diff запитом до агента, а не вручну постфактум;
- прив'яжемо approval до точного SHA і до названої дії;
- розведемо draft агента, deterministic check і рішення людини;
- застосуємо командну policy до конкретної зміни;
- перетворимо повторюваний збій на зміну спільного workflow.
| Claude Code | Автоматизація | Людина |
|---|---|---|
| досліджує, підсумовує, пропонує | звіряє SHA, запускає checks, блокує stale trace | визначає допустимість, затверджує, відповідає за результат |
Командне рішення про 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" і не став оцінювати залишковий ризик: він назвав рішення, якого бракує, і зупинився. Саме такої форми відповіді й варто вимагати - факти окремо, невирішене окремо.
- CI підтверджує checks на
a17c2e9, але не бере на себе залишковий ризик; - агент зібрав факти, а рішення лишається
HOLD, доки потрібний owner не дасть approval; - production readiness стосується версії change і конкретної дії, а не гілки взагалі.
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
CODEOWNERSвимагає review від власника sensitive path, а branch protection може зробити його approval обов'язковим;- dismiss stale approvals скидає рішення після будь-якого push, що змінює diff;
- правило approval most recent reviewable push вимагає свіжого підтвердження не від автора push;
- required checks і trace вказують current head SHA, а не лише номер PR.
Налаштування незалежні й часто вмикаються разом. Dismiss stale працює суворіше: підписи злітають усі разом, і в схвалений PR уже нічого не підмішати. Most recent push м'якше працює з PR, де кілька reviewer: старі approvals лишаються, достатньо одного свіжого - і не від того, хто пушив. Команді з єдиним reviewer це нічого не спрощує, а якщо правку запушить сам reviewer, підтвердити її стане нікому.
Claude може помітити новий diff. Гарантію свіжості дає правило платформи, а не уважність агента.
GO, HOLD чи SPLIT
Зелені checks не змушують обирати між беззастережним merge і повною відмовою. Іноді найкращий результат review - звузити change.
GO- current diff, evidence, owners і мета рішення збіглися;HOLD- бракує факту, owner або свіжого approval;SPLIT- доведена частина лишається, спірна authority boundary іде в окремий change.
Розвилка на схемі йде не за кольором 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, доказами і тією людиною, яка ухвалила обмежене рішення.
- Traceability показує шлях від intent до current diff і evidence;
- auditability дозволяє відновити, чому команда обрала саме це рішення;
- accountability називає власника рішення і наслідків;
- session ID допомагає розслідуванню, але не заміняє task spec, diff і review.
Кожна стрілка на схемі - передача відповідальності, а не запис у лог. Ліворуч завдання, праворуч назване рішення, а всередині diff прив'язаний до конкретного head SHA: саме ця прив'язка згодом дозволить відновити підстави.
Trace будується навколо переходів відповідальності, а не навколо кількості збереженого тексту.
Мінімальний trace
Запис має пережити скорочення і все одно пояснити рішення. Для PR #842 вистачає семи полів:
| Поле | Для кейсу |
|---|---|
| request / AI role | T-1841; implementation і tests |
| current head | b8f09d1 |
| changed | service, authz, audit event |
| verified | tests, lint, policy check |
| human control | plan confirmed; authz owner decides |
| open risk | role scope widened after review |
| decision | HOLD for merge; rollout не розглянуто |
- low-risk change вміщується в короткий запис PR;
- review-required change додає current SHA, owner і відкритий ризик;
- high-risk додає approvers, rollback і відомі обмеження до тієї самої секції PR або наявного decision record.
Хороший 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 за кілька секунд; рядок зі стенограми звіряти немає з чим. Тому в запиті перелічені потрібні поля, а не сказано "коротше".
- Claude перетворює шум сесії на draft, а ви звіряєте його з Git і checks;
AI-assistedфіксує спосіб роботи, але не знижує відповідальність автора;- зберігати потрібно підставу рішення, а не стенограму співпраці з моделлю.
Межі audit trail
Більше telemetry не означає більше accountability. Спочатку команда обирає, на яке питання має відповісти запис, і лише потім вмикає збір.
- OpenTelemetry export у Claude Code вмикається явно і потребує обраного backend;
- base events дають обмежені event metadata; identity додається автоматично в OAuth- і gateway-сесіях, а для API key, Bedrock, Google Cloud Agent Platform і Foundry її налаштовують окремо;
- targets і arguments команд вмикаються окремим прапорцем - там опиняються шляхи, команди і подекуди secrets;
- prompt, response, full tool content і raw API bodies потребують окремого opt-in і storage boundary.
| Рівень | Що отримує команда | Ціна |
|---|---|---|
| base events | session, event, decision | низька після налаштування export |
| tool details | paths, commands, MCP і skill names | можливі PII і secrets в arguments |
| raw content | розмова і повні bodies | окреме сховище чутливих даних |
Не плутайте це з особистим журналом сесії. Хук, який дописує ваші промпти у файл репозиторію, - ваш робочий слід: ви його завели, ви його й видалите. Командний audit trail зберігає чужі ідентичності, живе за retention і доступами, і правила в нього суворіші.
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 за хвилину, читають, а ту, яку треба вичитувати цілком, обходять.
human_onlyпотребує рішення людини;prohibitedлишається за межами workflow для всіх учасників;- спільна мова policy не передає агентові право схвалювати власний output.
Правило, owner, enforcement
Правило працює лише тоді, коли зрозуміло, хто його змінює, де воно виконується і чим це підтверджується.
| Rule | Owner | Mechanism | Evidence |
|---|---|---|---|
| owner для authz path | security-owner | CODEOWNERS, required code owner review, dismiss stale | approval на current head |
| trace на current head | developer-productivity-owner | власний required check trace-head-check | status на PR head SHA |
| policy доступна агентові | repository-policy-owner | import або інструкція в CLAUDE.md | rule і next step в output |
CLAUDE.mdспрямовує, але не дає жорсткого enforcement;- required check блокує stale trace, protected branch блокує merge без owner;
- owner відповідає за правило, exception path, зміни і retirement.
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
Схема розводить два потоки, які легко переплутати. Згори йде змістовний draft від Claude, знизу - фактичний head PR, а порівнює їх перевірка, яка нічого не вирішує: required status дає CI, а не рядок у SKILL.md. Рішення людини стоїть після зеленого статусу, а не замість нього.
- порівняння повторюється після кожного push, а не один раз під час створення note;
- червоний
trace-head-check- не помилка агента, а сигнал перегенерувати trace; - trace живе рівно один commit, і його свіжість доводить механізм, який не питає думки агента.
Pilot спільного активу
Demo від автора відповідає на питання "чи працює в мене". Спільний AI-актив має відповісти на інше: чи зможе другий розробник отримати той самий корисний результат без підказок автора.
Ключовий вузол на схемі - запуск другим користувачем, а не рішення в кінці. До нього в команди є лише враження автора, після - вимірювані промахи і переробки, за якими вже можна обирати між adopt, fix і retire.
Pilot окремо перевіряє output Claude з pr-trace і здатність trace-head-check ловити stale SHA.
- до pilot потрібні owner, очікуваний output і off-switch;
- другий користувач звіряє note з Git і PR evidence;
- рахуємо second-user success, пропущені поля, false positives, ручні переробки і bypasses;
- README, changelog і support boundary потрібні до того, як використання стане обов'язковим для всієї команди.
Спільний AI-актив готовий після відтворюваного результату другого користувача, а не після переконливого demo автора.
Inventory і revalidation
Для одного активу inventory вміщується в README. Цінність не в окремій системі, а в тому, щоб команда знала версію, власника, останнє evidence і швидкий disable path.
| Поле | Приклад |
|---|---|
| asset / version | pr-trace@1.3.0 + trace-head-check@0.4.0 |
| owner | developer-productivity-owner |
| last validation | second-user pilot on 8 PR fixtures |
| disable path | make check non-required; pin previous workflow |
Підставою для revalidation стає не сам календар, а зміна межі:
- новий model, provider або runtime mode;
- розширення tools, permissions, data class або external integration;
- нова версія skill, checker, plugin, MCP server або hook bundle;
- incident, стійкий bypass або помітний drift результатів.
Текст 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 |
- немає окремого стандарту якості для
AI codeіhuman code; - blameless-розбір не скасовує owner і термін follow-up;
- культура вимірюється реакцією на неприємний сигнал, а не повнотою списку принципів.
Петля покращення workflow
Поточний PR можна повернути в безпечний стан сьогодні. Системне виправлення потребує окремого власника, перевірки і часу, тому Claude готує draft, але не оголошує роботу закритою.
Підготуй draft postmortem для PR #842.
Розділи immediate containment і system follow-up.
Запропонуй owner, verification і stop condition.
Не став done без evidence нового pilot.
| Сьогодні | Окремий follow-up |
|---|---|
PR повернувся у HOLD | T-1860 виправляє skill і checker |
SUPPORT_AGENT винесений у T-1859 | owner призначений, термін визначений |
head c41d72a отримав approval | verification на 8 PR fixtures |
GO дозволяє лише merge | status 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.