ci: review anchors are taken after the pipeline's rebase, not before

The material anchors (commit, tree, spec blobs) written into every
review document came from the checkout step, before "Привести ветку к
dev". Whenever dev had moved — since 09.09 every review-document publish
moves it — the pipeline rebased and force-pushed the branch, orphaning
the pre-rebase commit and its tree. A fresh clone in the next run could
not resolve that tree: reuse (#499) always reported false and the
model reviewed the same code again, and the #413 post-step refused the
green round because neither the cited SHA nor the tree anchor was
reachable — #508 took three identical green rounds this way.

The `material` step, which already fixes the reviewed SHA after the
rebase, now also records the tree and spec blobs, and the publish step
reads all three from it. The contract test pins the order and forbids
reading anchors from the checkout step.

Issue: #515
User-Visible: no
This commit is contained in:
Codex
2026-09-10 00:04:41 +03:00
parent 3c1b4ebee2
commit 5a1cddeaf0
2 changed files with 45 additions and 18 deletions
+26 -18
View File
@@ -321,20 +321,10 @@ jobs:
git checkout -q "origin/$branch"
echo "материал ревью: ветка $branch, $(git rev-parse --short HEAD)"
echo "name=$branch" >> "$GITHUB_OUTPUT"
# Якоря материала, устойчивые к ребейзу (#413, #414). SHA коммита
# ребейз меняет — содержимое нет: git адресует деревья и блобы их
# хешем. Снимаются здесь, где рабочая копия ЕЩЁ равна тому, что
# ревьюер прочтёт; в шаге публикации дерево уже сброшено на целевую
# ветку, и спрашивать его поздно.
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
echo "tree=$(git rev-parse 'HEAD^{tree}')" >> "$GITHUB_OUTPUT"
# ТЗ задачи: блоб переживает и ребейз, и удаление ветки, пока текст
# где-нибудь достижим. Файлов может не быть (инфраструктурная
# задача) или быть несколько (разбитое ТЗ) — тогда список пуст либо
# длиннее одного.
specs=$(git ls-files -s -- "docs/specs/${NUM}-*.md" \
| awk '{print $2" "$4}' | tr '\n' ';')
echo "specs=$specs" >> "$GITHUB_OUTPUT"
# Якоря материала (sha, tree, specs) снимает шаг `material` — ПОСЛЕ
# ребейза (#515): снятые здесь, они после force-push приведённой
# ветки указывали на осиротевший коммит, и ни reuse (#499), ни
# страховка #414 не находили дерева в свежем клоне.
else
echo "::warning::ветка issue/${NUM}-* не найдена на origin — ревью пойдёт по dev"
echo "МАТЕРИАЛ НЕ ЗАПУШЕН" >> "$GITHUB_STEP_SUMMARY"
@@ -413,9 +403,26 @@ jobs:
- name: Зафиксировать SHA материала ревью
id: material
if: steps.rebase.outputs.conflict != 'true'
env:
NUM: ${{ github.event.issue.number }}
run: |
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
echo "материал ревью: $(git rev-parse --short HEAD)"
# Якоря материала, устойчивые к ребейзу (#413, #414). SHA коммита
# ребейз меняет — содержимое нет: git адресует деревья и блобы их
# хешем. Снимаются здесь, ПОСЛЕ приведения к dev (#515): рабочая
# копия равна тому, что ревьюер прочтёт, и коммит с этим деревом
# уже запушен в ветку — следующий прогон найдёт его в свежем клоне.
# В шаге публикации дерево уже сброшено на целевую ветку, и
# спрашивать его поздно.
echo "tree=$(git rev-parse 'HEAD^{tree}')" >> "$GITHUB_OUTPUT"
# ТЗ задачи: блоб переживает и ребейз, и удаление ветки, пока текст
# где-нибудь достижим. Файлов может не быть (инфраструктурная
# задача) или быть несколько (разбитое ТЗ) — тогда список пуст либо
# длиннее одного.
specs=$(git ls-files -s -- "docs/specs/${NUM}-*.md" \
| awk '{print $2" "$4}' | tr '\n' ';')
echo "specs=$specs" >> "$GITHUB_OUTPUT"
echo "материал ревью: $(git rev-parse --short HEAD), дерево $(git rev-parse --short 'HEAD^{tree}')"
# Повторное применение зелёного вердикта без вызова модели (#499). Сценарий
# #437 r4: зелёный r3 не слился (страж #312), задача вернулась в S6 и тут же
@@ -849,9 +856,10 @@ jobs:
STAGE: ${{ needs.guard.outputs.stage }}
CYCLE: ${{ needs.guard.outputs.cycle }}
SOURCE: ${{ runner.temp }}/review-document.md
MATERIAL_SHA: ${{ steps.branch.outputs.sha }}
MATERIAL_TREE: ${{ steps.branch.outputs.tree }}
MATERIAL_SPECS: ${{ steps.branch.outputs.specs }}
# После ребейза конвейером — якоря приведённого материала (#515).
MATERIAL_SHA: ${{ steps.material.outputs.sha }}
MATERIAL_TREE: ${{ steps.material.outputs.tree }}
MATERIAL_SPECS: ${{ steps.material.outputs.specs }}
# Вердикт из structured_output попадает в блок якорей (#499): по нему
# следующий заход решает, можно ли применить зелёный вердикт повторно.
OUT: ${{ steps.review.outputs.structured_output }}