Регистрация косяка агента в системе учёта WP-316 L1. Без LLM — детерминированный скрипт без WP Gate.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Peer-сессия DP.SC.154 где Kimi = писатель, Claude = напарник. Запускается простой фразой. Включает ОРЗ Opening и Closing, turn-loop, эскалации, Decision Gate (зафиксировать vs реализовать → ревью → проверить → задеплоить), отложенную финализацию и верификацию.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Задача: $ARGUMENTS
Архитектура: я (Kimi) = писатель, Claude = напарник. Claude вызывается через
claude-peer-adapter.shнапрямую — Bash tool, stdin pipe.list_peer_statuses(Local Gateway) — координация файлов, не проверка доступности Claude CLI. Gateway offline ≠ Claude недоступен.
Peer-сессия DP.SC.154 где Kimi = писатель, Claude = напарник. Запускается простой фразой. Включает ОРЗ Opening и Closing, turn-loop, эскалации, Decision Gate (зафиксировать vs реализовать → ревью → проверить → задеплоить), отложенную финализацию и верификацию.
Peer-сессия пригодна для: технических решений, дизайна, code review, поиска компромисса между подходами, подготовки кандидатов к решению. НЕ пригодна для решений, которые процесс явно закрепляет за человеком (например, R15 Валидатор в
/apply-captures— accept/reject/defer кандидатов знания; R1 Стратег — приоритеты месяца). Согласие двух агентов между собой — не решение пилота, даже единогласное и хорошо обоснованное.Если задача внутри пир-сессии требует такого решения — писатель обязан остановиться и спросить пилота напрямую в текущем чате (не через turn-файл), прежде чем фиксировать результат. См.
.claude/skills/apply-captures/SKILL.mdраздел «R15 = живой пилот, не агент» и${IWE_GOVERNANCE_REPO:-DS-strategy}/inbox/bugs/bug-2026-07-07-r15-decisions-bypassed-pilot.md— прецедент, из-за которого добавлено это ограничение.
Определить режим из $ARGUMENTS:
--list → прочитать ${IWE_GOVERNANCE_REPO:-DS-strategy}/sessions/00-index.md, вывести таблицу. Стоп.--interrupt <id> → перейти к Шагу 5 (interrupt-режим). Стоп после.--finalize <id> → перейти к Шагу 6 (finalize-режим). Стоп после.Та же проверка, что ~/.kimi-code/skills/session-open/SKILL.md уже делает для standalone-сессий Kimi (Ф33, 31.07) — до этой правки у пир-сессий Kimi-писателя не было НИКАКОЙ проверки, что сессия открыта честно (тот же класс дыры, что Ф28). Скрипт поставляется шаблоном; звать по конвенции путей (#566 — фантомным был только хардкод $HOME/IWE/scripts/..., сам скрипт существует и входит в манифест):
bash "${IWE_SCRIPTS:-$HOME/IWE/scripts}/kimi-standalone-preflight.sh"
ERROR: Kimi standalone session is NOT OPEN) → СТОП. Не переходить к Шагу 0б, не открывать WP Gate, не создавать meta.yaml/00-writer.md, не трогать файлы. Показать пилоту команду открытия из stderr скрипта (bash "${IWE_SCRIPTS:-$HOME/IWE/scripts}/session-guard.sh" open --wp WP-N --task "..." --agent kimi) и ждать, пока сессия не будет открыта явно.Найти WP по задаче: прочитать ${IWE_GOVERNANCE_REPO:-DS-strategy}/WP-REGISTRY.md (grep по ключевым словам) и ${IWE_GOVERNANCE_REPO:-DS-strategy}/current/WeekPlan W{N}.md.
Анонс пилоту:
Открываю peer-сессию (DP.SC.154)
Роль: Писатель (Kimi) | Напарник: Claude
Задача: <задача>
РП: WP-NNN «<название>» | или: не найден в плане
Метод: turn-loop ≤10 ходов | Модель напарника: Sonnet
Если РП не найден в плане недели → полный WP Gate Ритуал (memory/protocol-open.md §Сессия):
объявить артефакт + дождаться подтверждения пилота → только после «да» переходить к Шагу 1.
Если РП найден → продолжать без ожидания.
SESSIONS_DIR="${IWE_WORKSPACE:-$HOME/IWE}/${IWE_GOVERNANCE_REPO:-DS-strategy}/sessions"
TODAY=$(date +%Y-%m-%d)
MONTH=$(date +%Y-%m)
DAY=$(date +%d)
DAY_DIR="$SESSIONS_DIR/$MONTH/$DAY"
mkdir -p "$DAY_DIR"
NUM=$(printf "%02d" $(( $(find "$DAY_DIR" -maxdepth 1 -type d -name "${TODAY}-[0-9][0-9]-*" 2>/dev/null | wc -l | tr -d ' ') + 1 )))
Slug = первые 4 латинских слова из задачи строчными буквами через дефис (не-латиница и дата убираются). Никакой даты в slug — она уже в SESSION_ID. Если латиницы нет → session.
SESSION_ID="${TODAY}-${NUM}-${SLUG}"
SESSION_DIR="${DAY_DIR}/${SESSION_ID}"
1.1 Создать папку:
mkdir -p "$SESSION_DIR"
1.2 Записать meta.yaml (Write):
task_id: ""
date: "<TODAY>"
session_id: "<SESSION_ID>"
start_time: "<ISO-8601 UTC>"
end_time: ""
writer_agent: "kimi-headless"
peer_agent: "claude-code"
peer_cmd: "claude-peer-adapter"
peer_model: "sonnet"
status: "started"
turns_count: 0
turns_limit: 10
escalations_count: 0
extensions: []
result_path: ""
task_description: "<задача>"
implementation_pipeline: false
review_iterations: 0
verify_status: ""
deploy_shas: {}
# Двухосная модель (WP-367 Ф5, DP.SC.154 v4):
roles: {} # {agent_id: [DP.ROLE.NNN, ...]} после consensus в Opening
discovery_turns: 0 # сколько ходов ушло на role-discovery (не считается в turns_limit)
ad_hoc_roles: {} # {role_name: {agent_id, rationale, first_used_turn}} — для каскада audit
swap_history: [] # [{turn, from, to, reason}] — журнал SWAP_WRITER переходов
Если пилот не назначил роли при запуске сессии — initiator (writer/Kimi) в ход 0 предлагает свою content-role и роль напарника (см. DP.SC.154 раздел «Opening сессии: Sequential role-discovery»). Discovery-ходы (0-2) не входят в turns_limit: 10.
In-session ad-hoc role signal (DP.SC.154 v4, каскад Pack-расширения уровень 1). При использовании ad-hoc роли (нет в Pack DP.ROLE.NNN/MIM.R.NNN/VR.R.NNN) Kimi-писатель обязан сразу объявить пилоту:
Беру ad-hoc роль «<имя>». В каталоге Pack такой нет.
Обязанности: <одной строкой>. Метод: <одной строкой>.
Предлагаю создать РП на формализацию (~30 мин).
Выбери:
А. Создать сейчас → отдельный РП «pack-gap-<имя>».
Б. Отложить → продолжу как ad-hoc, сторож напомнит при Week Close.
Запись в meta.yaml.ad_hoc_roles идёт независимо от выбора (для back-up уровня 2). При выборе А — после сессии писатель открывает отдельный РП.
1.3 Добавить строку в sessions/00-index.md сверху таблицы (первая строка таблицы после |---|):
| <TODAY> | <SESSION_ID> | <задача ≤50 симв> | kimi / claude-code | 0 | 0 | started | — |
Записать ${SESSION_DIR}/00-writer.md (Write):
---
turn: 0
role: writer
agent_id: kimi-headless
timestamp: <ISO-8601 UTC>
consensus: none
---
<Моя начальная позиция — анализ задачи, тезисы, конкретные вопросы к напарнику.
НЕ пересказ задачи. Позиция с аргументами.>
Показать пилоту краткое резюме: что написал в 00-writer.md.
Переменные: TURN=1, ESCALATIONS=0, DONE=false.
Прочитать все предыдущие реплики из SESSION_DIR в порядке нумерации.
Составить промпт:
КРИТИЧНО: Твоя задача — ТОЛЬКО написать одну peer-реплику в stdout с frontmatter.
Запрещено: редактировать файлы, делать commit, git push, создавать файлы в SESSION_DIR.
Весь твой ответ = одна реплика в stdout. Ничего больше.
Ты — напарник (peer agent) в диалоговой сессии (DP.SC.154).
Сессия: <SESSION_ID>
Ход: <TURN> из 10
Задача: <задача>
Прочитай все файлы журнала в <SESSION_DIR> по порядку (00-writer.md, 01-peer.md, ...).
Напиши реплику в stdout с frontmatter:
---
turn: <TURN>
role: peer
agent_id: claude-code
timestamp: <ISO-8601 UTC>
consensus: none | proposed | reached | escalate
---
<Твой ответ>
Правило критика: найди ХОТЯ БЫ ОДИН тезис или допущение писателя, с которым не согласен. Не сдавайся после первого возражения — держись аргументированно. Если всё действительно ОК — объясни почему конкретно, не просто «согласен».
Маркеры (строго в начале строки):
CONSENSUS: <резюме> — если считаешь что договорились
ESCALATE_TO_USER: <причина> — если писатель игнорирует существенное возражение
Перед вызовом Claude писатель добавляет в промпт минимальную текстовую проекцию предыдущих реплик и фактов. Claude не читает SESSION_DIR и не использует инструменты.
Вызов Claude через Bash:
PEER_FILE="${SESSION_DIR}/$(printf '%02d' $TURN)-peer.md"
echo "<промпт>" | bash "${IWE_WORKSPACE:-$HOME/IWE}/${IWE_GOVERNANCE_REPO:-DS-strategy}/scripts/claude-peer-adapter.sh" \
> "$PEER_FILE" 2> "${PEER_FILE%.md}.err"
Если файл пустой или exit ≠ 0 → сообщить пилоту: «Claude не ответил. Повторить или прервать?»
Прочитать $PEER_FILE. Вывести ключевые тезисы Claude (не всю реплику дословно — краткое резюме + цитаты ключевых позиций).
ESCALATE_TO_USER:
Если grep -q "^ESCALATE_TO_USER:" "$PEER_FILE":
grep "^ESCALATE_TO_USER:" "$PEER_FILE" | sed 's/^ESCALATE_TO_USER: //'ESCALATIONS += 1${SESSION_DIR}/escalation-$(printf '%02d' $((ESCALATIONS-1))).md:---
escalation_number: <N>
turn: <TURN>
timestamp: <now>
reason: "<причина>"
pilot_response: ""
---
# Эскалация <N> (ход <TURN>)
**Причина:** <причина>
**Реплика Claude:** <PEER_FILE>
**Ответ пилота:** (ввести ниже)
pilot_response в escalation-файл.meta.yaml: escalations_count: <ESCALATIONS> (Bash sed).CONSENSUS:
Если grep -q "^CONSENSUS:" "$PEER_FILE":
DONE=true, перейти к Шагу 3.5 (Decision Gate) — НЕ к Шагу 4 напрямую.Если TURN >= 10 → DONE=true, перейти к Шагу 4.
Написать $(printf '%02d' $((TURN+1)))-writer.md (Write):
---
turn: <TURN+1>
role: writer
agent_id: kimi-headless
timestamp: <now>
consensus: none
---
<Моя реплика: ответ на аргументы Claude + учёт направления пилота>
TURN += 1 → вернуться к 3.1.
Когда срабатывает:
DONE=trueчерез CONSENSUS-маркер в Шаге 3.3 (не черезTURN >= 10— там сразу Шаг 4). Зачем: консенсус ≠ реализация. Это легитимный choice-question для пилота (выбор объёма работы, не yes/no на готовое решение). Исключение из P5 — пилот сам подтвердил: «здесь от меня нужно согласование» (триггер 2026-05-30, WP-367 Ф5). Обязательно: перед запросом — краткое резюме консенсуса на пальцах, чтобы пилот мог осознанно выбрать. Запрос без резюме = механический «выберите А/Б» без понимания.
Извлечь резюме консенсуса (grep "^CONSENSUS:" "$PEER_FILE" | sed 's/^CONSENSUS: //').
Резюме на пальцах — обязательная часть. Формат (без технических терминов, кодов, путей):
Консенсус достигнут.
Что обсуждалось: <одной фразой>
К чему пришли: <2-3 строки человеческим языком — суть решения>
Что предлагается реализовать: <список изменений, по 1 строке каждое; без файлов, путей>
Сколько займёт реализация: ~<N>h (включая ревью + smoke + deploy)
Изменения у других пользователей: <если есть — что и как доставляется; если нет — «только локально»>
После резюме — choice question:
Что дальше?
А. Только зафиксировать → Шаг 4 (report.md + commit + close).
Реализация — отдельный РП/фаза при следующей сессии.
Б. Реализовать сейчас → ревью → проверить → задеплоить → Шаг 4.
Дождаться ответа пилота. Записать выбор в meta.yaml (Bash sed):
implementation_pipeline: false | true
IMPLEMENTATION=false, перейти к Шагу 4.IMPLEMENTATION=true, перейти к Шагу 3.6.Default при молчании пилота: Б (реализация сейчас), per правило 11 «финиш > отлог». Применять только если пилот явно не ответил в течение разумного времени.
Triggers automatic-defer (без запроса пилоту — сразу А):
При срабатывании trigger — анонс пилоту с резюме (НЕ запрос), потом Шаг 4.
Активируется: только при
IMPLEMENTATION=trueв Шаге 3.5. Принцип: Kimi-writer применяет решение → cold-context Claude через bash pipe делает code review → writer фиксит → Claude через bash pipe запускает smoke (writer не имеет Skill tool) → deploy → секция «Реализация и проверка» в report-draft.md. Архитектурное ограничение: Kimi-headless не имеет Agent/Skill tools. Все вызовы внешних агентов идут черезclaude-peer-adapter.sh(stdin pipe) — это осознанная асимметрия с/peer-conversation.
Анонс пилоту:
Реализация консенсуса <SESSION_ID>
Файлы: <list of files with absolute paths>
Репо: <repo names, separated by " · ">
Метод: Edit/Write tools напрямую
Writer (Kimi) применяет изменения через Edit/Write. Запрещено:
Зафиксировать список изменённых файлов в CHANGED_FILES (один путь на строку).
Переменные итерации ревью: REVIEW_ITER=1 при первом входе, инкрементируется в 3.6.3.
Вызов Claude как code reviewer через тот же адаптер что для turn-loop:
: "${REVIEW_ITER:=1}"
REVIEW_FILE="${SESSION_DIR}/review-$(printf '%02d' "$REVIEW_ITER").md"
REVIEW_PROMPT=$(cat <<EOF
КРИТИЧНО: НЕ используй Write/Edit. Выводи markdown в stdout.
Весь твой ответ = один отчёт в stdout. Ничего больше.
Cold-context code review результатов peer-сессии <SESSION_ID>.
Ты — независимый ревьюер, не видевший диалога. Контекст ниже.
Резюме консенсуса: <CONSENSUS_SUMMARY>
Изменённые файлы:
<CHANGED_FILES>
У тебя нет файловых инструментов и доступа к каталогу сессии — весь нужный код уже вставлен выше, в `<CHANGED_FILES>` (диф и фрагменты файлов, добавляет писатель перед вызовом).
Проверь по чек-листу:
1. asyncio runtime: ищи 'wait_for(coro)' без 'shield' → coroutine reuse. Fire-and-forget tasks читающие/пишущие одну строку БД из разных мест.
2. Shell ordering: function call ДО function definition. 'set -u' соблюдён?
3. SQL race: cross-file writers в одну строку без атомарности (UPDATE ... RETURNING / SELECT FOR UPDATE).
4. Lock enforcing: при collision — 'exit N' или 'log WARN && continue'? Если advisory — это intentional или баг?
5. Контекст-специфика консенсуса: <дополни из резюме если есть инварианты>.
Верни отчёт в формате:
## Critical (must fix before deploy)
- <file:line-range>: <issue> | fix: <conkr>
## High / ## Medium / ## OK
Не предлагай рефакторинг или стиль — только runtime баги и нарушения чек-листа.
EOF
)
echo "$REVIEW_PROMPT" | bash "${IWE_WORKSPACE:-$HOME/IWE}/${IWE_GOVERNANCE_REPO:-DS-strategy}/scripts/claude-peer-adapter.sh" \
> "$REVIEW_FILE" 2> "${REVIEW_FILE%.md}.err"
Добавь в REVIEW_PROMPT точечный diff и нужные фрагменты файлов. Нельзя передавать каталоги: Claude получает только текстовую проекцию.
Прочитать $REVIEW_FILE. Показать пилоту краткое резюме (Critical + High count + один пример).
Если есть Critical:
REVIEW_ITER += 1 → вернуться к 3.6.2 (новый review-NN.md).ESCALATE_TO_USER: + escalation-NN.md.Если только High/Medium:
review_iterations: <N>, unresolved: <count>).Если только OK:
Kimi-writer не имеет Skill tool — /verify вызывается через Claude как proxy:
VERIFY_FILE="${SESSION_DIR}/verify-01.md"
VERIFY_PROMPT=$(cat <<EOF
КРИТИЧНО: НЕ используй Write/Edit для файлов вне временного smoke-скрипта. Выводи результат в stdout.
Весь твой ответ = один отчёт в stdout. Ничего больше.
Запусти smoke test для изменений peer-сессии <SESSION_ID>.
Изменённые файлы:
<CHANGED_FILES>
Инварианты консенсуса (что должно работать):
<list from 3.5>
Используй встроенный /verify skill (Skill tool: skill=verify, args=...).
Если /verify не подходит (например, CLI-only без UI) — напиши и запусти точечный smoke (pytest fixture / curl call / минимальный python script).
Верни:
- PASS / FAIL
- При FAIL: traceback + первая строка-причина
- Команда которую запустил
EOF
)
echo "$VERIFY_PROMPT" | bash "${IWE_WORKSPACE:-$HOME/IWE}/${IWE_GOVERNANCE_REPO:-DS-strategy}/scripts/claude-peer-adapter.sh" \
> "$VERIFY_FILE" 2> "${VERIFY_FILE%.md}.err"
Claude в этом вызове не запускает smoke-тесты: он может только оценить переданный текст. Исполняемую проверку запускает писатель локально по отдельному протоколу.
Результат:
Для каждого репо в списке изменённых файлов:
(cd <repo path>
git status --short
# pathspec после `--`: commit ТОЛЬКО свои файлы. Bare `git commit` сметает
# чужое pre-staged из общего индекса (mis-attribution, см. 2026-06-20-39).
git add <specific files — НЕ git add . и НЕ git add -u>
git commit -m "<type>(<scope>): <короткое описание>
Refs: peer-session <SESSION_ID>
Review iters: <REVIEW_ITER>
Verify: PASS" -- <те же specific files>
git push
)
Записать commit SHA для каждого репо в DEPLOY_SHAS (map: repo → sha).
Если push fail:
--no-verify запрещён правилом 6 CLAUDE.md).В ${SESSION_DIR}/_outcome.md (Write) — служебный файл для синтезатора:
## Реализация и проверка
**Изменённые файлы:**
<CHANGED_FILES with one-line description each>
**Code review итераций:** <REVIEW_ITER>
**Unresolved (отложено на потом):** <count High/Medium или «нет»>
**Smoke verification:** PASS | FAIL (с пометкой что fix'нули)
**Deploy:**
- <repo1>: commit <sha1>
- <repo2>: commit <sha2>
**Открытые задачи после deploy:** <список или «нет»>
Этот файл будет включён синтезатором (Шаг 4.2) как обязательная секция при implementation_pipeline: true.
Почему здесь: пир-сессия — тоже сессия работы, вопрос рефлексии обязателен так же, как и в обычной Quick Close (Ф18) — этот же разрыв найден и закрыт 30.07 в
peer-conversation/SKILL.md(Claude-писатель); здесь тот же фикс для симметричного случая (Kimi-писатель, Claude-напарник). Порог и формулировка идентичны — Claude (напарник) остаётся тем, у кого есть живой канал с пилотом и доступ к Skill/Bash, поэтому шаг ниже исполняет напарник, не писатель.
Порог: та же формула, что в peer-conversation/SKILL.md §3.7 (переиспользует починенный в gather-session-facts.sh, WP-484 Ф26, разбор даты — не изобретать заново):
START_TIME=$(grep '^start_time:' "$SESSION_DIR/meta.yaml" | sed -E 's/^start_time: *"?([^"]*)"?$/\1/')
NOW_EPOCH=$(date -u +%s)
START_EPOCH=$(date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$START_TIME" +%s 2>/dev/null \
|| date -u -d "$START_TIME" +%s 2>/dev/null \
|| echo "$NOW_EPOCH")
DURATION_MIN=$(( (NOW_EPOCH - START_EPOCH) / 60 ))
Если DURATION_MIN ≤ 15 — пропустить, перейти к Шагу 4 молча.
Если duration_min > 15:
CONCEPT-night-cycle.md §18).LEDGER_SCRIPT="${IWE_WORKSPACE:-$HOME/IWE}/${IWE_GOVERNANCE_REPO:-DS-strategy}/scripts/ledger-append.sh"
if [ -f "$LEDGER_SCRIPT" ]; then
bash "$LEDGER_SCRIPT" day "$(date +%F)" session_reflection "{\"wp\": \"<WP-NNN>\", \"answer\": <экранированный ответ>}" kimi-peer-writer
else
echo "ledger-append.sh недоступен на этой установке — рефлексия не записана в дневной ledger"
fi
Пропуск ответа — не блокировать: "answer": "нет ответа", продолжить Шаг 4.
TURNS_DONE=$(find "$SESSION_DIR" -maxdepth 1 -name "[0-9][0-9]-*.md" | wc -l | tr -d ' ')
END_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
tmpf=$(mktemp)
sed "s/^status:.*/status: \"completed\"/" "$SESSION_DIR/meta.yaml" |
sed "s/^end_time:.*/end_time: \"$END_TIME\"/" |
sed "s/^turns_count:.*/turns_count: $TURNS_DONE/" |
sed "s/^escalations_count:.*/escalations_count: $ESCALATIONS/" > "$tmpf"
mv "$tmpf" "$SESSION_DIR/meta.yaml"
Архитектурное ограничение: Kimi-писатель использует bash pipe через
claude-peer-adapter.sh, т.к. Kimi не имеет доступа к Claude Agent tool. Claude-писатель (скилл/peer-conversation) использует Agent tool — это осознанное различие, а не дрейф.
Запустить Claude как синтезатора через bash pipe (context isolation через stdin):
python3 - "$SESSION_DIR" "$SESSION_ID" <<'PYEOF'
import sys, os, glob, subprocess, datetime
session_dir, session_id = sys.argv[1:3]
# Read meta
meta_path = os.path.join(session_dir, 'meta.yaml')
meta = {}
with open(meta_path, encoding='utf-8') as f:
for line in f:
if ':' in line and not line.strip().startswith('#'):
k, v = line.split(':', 1)
meta[k.strip()] = v.strip().strip('"').strip("'")
writer_agent = meta.get('writer_agent', '')
peer_agent = meta.get('peer_agent', '')
start_time = meta.get('start_time', '')
escalations_count = meta.get('escalations_count', '0')
task_desc = meta.get('task_description', '')
# Gather turns
turn_files = sorted(glob.glob(os.path.join(session_dir, '[0-9][0-9]-*.md')))
turns_text = ''
for tf in turn_files:
fname = os.path.basename(tf)
with open(tf, encoding='utf-8') as f:
body = f.read()
turns_text += f'\n\n=== {fname} ===\n{body}'
outcome_path = os.path.join(session_dir, '_outcome.md')
outcome_text = ''
if os.path.exists(outcome_path):
with open(outcome_path, encoding='utf-8') as f:
outcome_text = f.read()
# Consistency guard: _outcome.md отсутствует, но meta говорит implementation_pipeline: true
if not outcome_text and meta.get('implementation_pipeline', 'false').lower() == 'true':
import re as _re
with open(meta_path, encoding='utf-8') as _f:
_mc = _f.read()
_mc = _re.sub(r'^implementation_pipeline:.*$', 'implementation_pipeline: false', _mc, flags=_re.MULTILINE)
with open(meta_path, 'w', encoding='utf-8') as _f:
_f.write(_mc)
meta['implementation_pipeline'] = 'false'
synth_prompt = f"""Ты — синтезатор итогов диалога двух агентов (DP.SC.154).
Задача сессии: {task_desc}
Ниже — полная стенограмма диалога (реплики в порядке нумерации):
{turns_text}
Прочитай `meta.yaml` в той же папке — извлеки `roles`, `ad_hoc_roles`, `discovery_turns` для §1.5.
{('Дополнительно — outcome реализации (источник для §6):' + chr(10) + outcome_text) if outcome_text else 'Implementation pipeline не запускался — §6 omit.'}
КРИТИЧНО: НЕ используй Write/Edit. Выводи markdown в stdout — он будет записан в report-draft.md.
Не оборачивай в ```markdown``` — пиши markdown напрямую.
Инвариант: result_class=agreed → §4 непустой; not-agreed → §4 = «Консенсус не достигнут».
§6 обязательна если есть _outcome.md; omit если нет.
Verify-якоря обязательны для код-ссылок (file:line-range). Теги [synthesized] в §4.
СТИЛЬ: разговорный для пилота (DP.SC.050 A1-A11). Перепиши, не копируй turn-файлы. Замени технические термины на бытовые, убери машинные маркеры (PASS, SHA, exit), активный залог.
---
schema_version: 1
session_id: {session_id}
generated_at: {datetime.datetime.now(datetime.timezone.utc).isoformat().replace('+00:00', '')}Z
writer: {writer_agent}
peer: {peer_agent}
duration_min: <(end_time − start_time) в минутах, целое>
escalations_count: {escalations_count}
result_class: agreed | partial | escalated | not-agreed
confidence: low | med | high
confidence_basis: <обязателен если confidence <= med; иначе omit>
ttl_event: <«до merge PR-NNN» | «до WP-NNN» | «до отмены пилотом» | omit>
cost_usd: <если известно; иначе omit>
cost_source: api | estimated | missing
roles: <из meta.yaml: roles — {{agent_id: [DP.ROLE.NNN, ...]}} или omit если пусто>
ad_hoc_roles: <из meta.yaml: ad_hoc_roles — {{role_name: {{agent_id, rationale, first_used_turn}}}} или omit если пусто>
discovery_turns: <из meta.yaml: discovery_turns, целое; omit если 0>
---
# Итоговый отчёт
## Algorithm
## 1. Исходная постановка
- **Задача:** <цитата из задания пилота, дословно>
- **Первоначальная позиция писателя:** <если зафиксирована в 00-writer.md; omit если нет>
## 1.5 Роли участников
Omit если `roles` пусто и `ad_hoc_roles` пусто.
**Форменные роли:**
- Писатель: <writer_agent>
- Напарник (критик): <peer_agent>
**Содержательные роли (content-roles):**
- <agent_id>: <роль> (источник: Pack `DP.ROLE.NNN` | ad-hoc | не назначена)
- ...
**Ad-hoc роли (если есть):**
- «<имя>» — <agent_id>, <рационал>, впервые использована в ходе <first_used_turn>
**Discovery:** <discovery_turns> ходов ушло на согласование ролей (не считались в лимит).
## 2. Позиции по темам
Под каждой темой (затронута обеими сторонами и повлияла на итог):
**Тема N: <формулировка>**
- Инициатор: писатель | напарник
- **Писатель:** тезис → обоснование → якорь (file:line-range / Pack-ID)
- **Напарник:** тезис → обоснование → якорь
- Эволюция (опц.): если позиция менялась — ход и причина
- Разрешение: что приняли + чей аргумент перевесил
## 3. Отвергнутые альтернативы
Omit если пусто. Только аргументированные обеими сторонами ИЛИ отвергнутые с контраргументом.
- Альтернатива → причина отказа → ссылка на ход
## 4. Зафиксированное решение
- <Исполняемая формулировка> [synthesized]
- **Главный аргумент:** <одной строкой>
- **Confidence:** low | med | high (если ≤ med — обоснование обязательно)
- **TTL-event:** <привязка к событию или omit>
Инвариант: agreed → непустой; not-agreed — «Консенсус не достигнут».
## 5. Открытые вопросы и эскалации
Omit если пусто.
- <Вопрос или эскалация>
- Статус: needs-decision | needs-verification | deferred
- Ссылка: escalation-NN.md или NN-peer.md (если есть)
## 6. Реализация и проверка
Omit если `implementation_pipeline: false` в meta.yaml.
Если true — обязательная секция, источник = `_outcome.md` в этой же папке.
- **Изменённые файлы:** список с one-line описанием каждого
- **Code review итераций:** <N>
- **Unresolved:** <count High/Medium или «нет»>
- **Smoke verification:** PASS | FAIL
- **Deploy:** repo → commit SHA (по каждому затронутому репо)
- **Открытые задачи после deploy:** список или «нет»
- **Ссылки:** review-NN.md, verify-NN.md
## 7. Метаданные и навигация
- **Журнал:** ссылки на все NN-writer.md / NN-peer.md по порядку
- **Связанные артефакты:** Pack-IDs, файлы (PR, спецификации) — если упоминались
- **Стоимость:** $X (источник: api / estimated / missing) — omit если missing
"""
import tempfile
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False, encoding='utf-8') as tmp:
tmp.write(synth_prompt)
tmp_path = tmp.name
report_file = os.path.join(session_dir, 'report-draft.md')
gov_repo = os.environ.get('IWE_GOVERNANCE_REPO', 'DS-strategy')
adapter = os.path.expanduser(f'~/IWE/{gov_repo}/scripts/claude-peer-adapter.sh')
# synth_prompt above already inlines the full transcript, meta.yaml fields and
# _outcome.md into stdin — claude-peer-adapter.sh is a text-only reviewer by
# contract (WP-458) and unconditionally rejects --add-dir (exit 64). Passing
# it here made every synthesis call fail deterministically, not just under
# some failure condition; found via code review, confirmed by Codex reading
# the same two files independently, peer-session
# 2026-08-04-08-wp7-f44-sandbox-review. stderr is now captured (not
# discarded) so a future regression leaves an actual diagnostic in the
# fallback stub below instead of the same generic guess every time.
stderr_path = tmp_path + '.err'
try:
with open(tmp_path, 'r', encoding='utf-8') as stdin_f, \
open(report_file, 'w', encoding='utf-8') as stdout_f, \
open(stderr_path, 'w', encoding='utf-8') as stderr_f:
try:
result = subprocess.run(
['bash', adapter],
stdin=stdin_f,
stdout=stdout_f,
stderr=stderr_f,
timeout=180
)
except (subprocess.TimeoutExpired, OSError):
# Any launch failure, not just a timeout, folds into the same
# returncode=1 path below — that branch already reads and cleans
# up stderr_path; a narrower except here left it leaking on the
# rarer OSError case (found in cold review, same peer-session).
result = subprocess.CompletedProcess(args=[], returncode=1)
finally:
os.unlink(tmp_path)
if result.returncode != 0 or os.path.getsize(report_file) == 0:
stderr_tail = ''
if os.path.exists(stderr_path):
with open(stderr_path, encoding='utf-8') as f:
stderr_tail = f.read()[-2000:]
os.unlink(stderr_path)
now = datetime.datetime.now(datetime.timezone.utc).isoformat().replace('+00:00', '') + 'Z'
with open(report_file, 'w', encoding='utf-8') as f:
f.write(f"""---
session_id: {session_id}
generated_at: {now}
note: синтез не выполнен (Claude недоступен, вернул пустой результат, или таймаут >180с)
---
# Итоговый отчёт
Стенограмма: см. файлы реплик в папке сессии.
Повтори синтез: `/peer-writer --finalize {session_id}`
## Диагностика (stderr адаптера, для отладки — не для пилота)
returncode: {result.returncode} {stderr_tail if stderr_tail else '(stderr пуст)'}
""")
sys.exit(1)
else:
if os.path.exists(stderr_path):
os.unlink(stderr_path)
PYEOF
Fallback: заглушка
report-draft.mdзаписывается изнутри python-блока выше (строкиif result.returncode != 0 or os.path.getsize(report_file) == 0). Внешнего bash-fallback не нужно —sys.exit(1)уведомляет shell, но скилл идёт дальше к Шагу 4.3 (заглушка уже на диске). Заглушка теперь несёт код возврата и хвост stderr адаптера — секция «Диагностика» служебная (для отладки), синтезатор её не видит и не переносит в финальный report.md.
Инвариант:
report.md— только финальная версия. До явного Close-сигнала от пилота файл называетсяreport-draft.md.
При консенсусе (turn ≤ 10):
report.md.закрывай, закрываем, всё, close, закрой — считать Close-сигналом и сразу переходить к финализации БЕЗ choice-question.mv "$SESSION_DIR/report-draft.md" "$SESSION_DIR/report.md"
затем перейти к шагу 4.3.## Дополнение (turns N–M, <timestamp>) в тот же report-draft.md, затем переименовать.При дозакрытии:
## Дополнение (turns N–M, <timestamp>)
### Turn N — <тема>
...
В meta.yaml:
extensions:
- turns: [4, 5, 6]
reason: "verification R23 + multiplier recalculation"
appended_at: "2026-05-23T04:25"
Запрещено:
report-v1.md, report-v2.md — одна сессия = один отчёт.sessions/YYYY-MM/DD/<id>/ = единое пространство.-writer.md/-peer.md при status: completed — статус меняется только после Close-сигнала.Найти строку с <SESSION_ID> и заменить целиком:
| <TODAY> | <SESSION_ID> | <задача ≤50> | kimi / claude-code | <TURNS> | <ESCALATIONS> | completed | [report.md](<MONTH>/<DAY>/<SESSION_ID>/report.md) |
(Bash awk — безопасен для строк с |.)
Slug-часть (без даты и номера): SESSION_SLUG=$(echo "$SESSION_ID" | sed -E 's/^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-//')
Записать ${IWE_GOVERNANCE_REPO:-DS-strategy}/sessions/<MONTH>/<TODAY>-<SESSION_SLUG>.md (Write) — Quick Close файл плоский под месячной папкой, без DD/ (симметрично session-guard.sh; DD/ — только для peer-session-папок):
---
date: <TODAY>
type: peer-session
writer: kimi-headless
peer: claude-code
duration_h: <(end_time - start_time) в часах, 1 знак>
artifacts: sessions/<MONTH>/<DAY>/<SESSION_ID>/report.md
session_id: <SESSION_ID>
wp: <WP-NNN или unknown>
---
# Главный инсайт
<1-2 строки из §4 report.md — зафиксированное решение>
(cd "${IWE_WORKSPACE:-$HOME/IWE}/${IWE_GOVERNANCE_REPO:-DS-strategy}"
# Pre-commit guard
test ! -f "$SESSION_DIR/report-draft.md" \
|| { echo "FAIL: report-draft.md существует — mv к report.md не выполнен"; exit 1; }
test -f "$SESSION_DIR/report.md" \
|| { echo "FAIL: report.md отсутствует"; exit 1; }
CLOSE_FILE="sessions/$MONTH/${TODAY}-${SESSION_SLUG}.md"
test -f "$CLOSE_FILE" \
|| { echo "FAIL: close-файл $CLOSE_FILE отсутствует"; exit 1; }
INDEX_COUNT=$(grep -cF "| $SESSION_ID |" "sessions/00-index.md" || echo 0)
test "$INDEX_COUNT" -eq 1 \
|| { echo "FAIL: 00-index.md: ожидается 1 запись для $SESSION_ID, найдено $INDEX_COUNT"; exit 1; }
# pathspec после `--`: commit ТОЛЬКО файлы сессии (mis-attribution, 2026-06-20-39)
# PR flow (WP-436 Ф2): push to feature branch + auto-merge PR → branch protection on main.
PATHS=("sessions/$MONTH/$DAY/$SESSION_ID/" "sessions/00-index.md" "sessions/$MONTH/${TODAY}-${SESSION_SLUG}.md")
BRANCH="peer/$SESSION_ID"
git checkout -b "$BRANCH" 2>/dev/null || git checkout "$BRANCH"
git add "${PATHS[@]}"
git commit -m "feat(peer): $SESSION_ID (kimi-writer) — <задача кратко>" -- "${PATHS[@]}"
git push origin "$BRANCH"
gh pr create --title "feat(peer): $SESSION_ID" \
--body "Peer-сессия DP.SC.154. Kimi (writer) + Claude (peer)." \
--base main --auto-merge 2>/dev/null \
|| echo "WARN: gh pr create failed — merge manually or check gh auth"
)
Показать пилоту: «Сессия завершена. Отчёт: sessions/$MONTH/$DAY/$SESSION_ID/report.md»
При --interrupt <session_id>:
MONTH=$(echo "$session_id" | cut -c1-7), DAY=$(echo "$session_id" | cut -c9-10) → найти sessions/$MONTH/$DAY/$session_id/meta.yaml.status: interrupted, end_time: <now>, turns_count: <число файлов>.<session_id> в sessions/00-index.md и заменить: статус → interrupted, report → —.При --finalize <session_id>:
MONTH=$(echo "$session_id" | cut -c1-7), DAY=$(echo "$session_id" | cut -c9-10). Проверить что папка sessions/$MONTH/$DAY/$session_id существует и содержит хотя бы 00-writer.md.meta.yaml — взять task_description, start_time, escalations_count.claude-peer-adapter.sh) с теми же инвариантами и fallback.meta.yaml (Bash sed): status: completed, end_time: <now>, turns_count: <число файлов>.sessions/00-index.md: статус → completed, report → ссылка.Используется для восстановления прерванных сессий без перезапуска turn-loop.
Для проверки любого существующего report.md написать в чат:
«проверь отчёт сессии <session_id>»
Запустить субагент (Sonnet, context isolation): прочитать все файлы сессии + report.md, сверить с инвариантами schema_version=1 (frontmatter, §4 непустой при agreed, verify-якоря).
<!-- USER-SPACE --> <!-- /USER-SPACE -->아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Регистрация косяка агента в системе учёта WP-316 L1. Без LLM — детерминированный скрипт без WP Gate.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Разбор extraction-reports со status pending-review — решение R15 (accept/reject/defer) ЖИВЫМ ПИЛОТОМ, запись в Pack, обновление статуса, коммит. Вызывать при Close при наличии N>0 pending-review отчётов.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Оценка архитектурного решения по 7 характеристикам ЭМОГССБ (v3.1 — фильтр допуска, атрибут-сценарии, совет затронутых сторон; профиль без агрегатного балла, conjunctive screening). Используй когда пользователь предлагает архитектурное решение, новый инструмент или системное изменение.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Classifies raw pilot request → structured JSON {task_type, class, artifact, budget_estimate, confidence, routing_tag, resolution_path, schema_version, result_type, expected_result_kind, result_kind_resolution, hypothesis_relation}. Keyword-fast (<200ms) or Haiku fallback (<60s). Does NOT create WP or call executor.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Audit repository documentation: detect drift between code and docs, report coverage by category. Run manually or on triggered drift critical.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Аудит пользовательской инсталляции IWE. Запускает scripts/iwe-audit.sh + MCP healthcheck + smoke-test ритуала через sentinel-механику (контракт dry-run-contract.md), передаёт отчёт subagent'у в роли VR.R.002 Аудитор (context isolation) → verdict ✅/⚠️/❌ по 6 компонентам (Inventory, L1 drift, {{GOVERNANCE_REPO}}, L3 customizations, MCP, ритуал). Используй после restore из бэкапа, после update.sh, или при еженедельной сверке.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.