Initial publish v0.1.0: standalone workflow core (corpus + examples + guards)
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
---
|
||||
name: land-batch
|
||||
description: >
|
||||
Use ONLY when the orchestrator lands the finished task branches of one DAG
|
||||
iteration as a single batch PR ([org-internal #3731] batch-landing pilot). Composes
|
||||
path-disjoint member branches via the deterministic batch-compose script,
|
||||
pre-validates locally, opens ONE PR for N tasks (one CI fan-out instead of
|
||||
N on the single-runner pool), pastes each member's review synthesis into
|
||||
the PR conversation, runs one delta-scoped review-code on the batch head,
|
||||
then hands the labeled PR to the merge coordinator. NOT for hotfixes /
|
||||
CI-infra fixes (fast lane: 1:1 PR), single tasks, or single-session
|
||||
mono-branch batches (topology A — one session owns every ticket on one
|
||||
branch from inception; hand-compose those, see Applicability).
|
||||
stage: merge-pr
|
||||
triggers:
|
||||
- land batch
|
||||
- batch land
|
||||
- batch-compose
|
||||
- 批量归并
|
||||
- 批量提交 pr
|
||||
role: Producer
|
||||
---
|
||||
|
||||
# land-batch — batch PR composition for one DAG iteration
|
||||
|
||||
**Orchestrator-only.** The composing session is the epic's orchestrator
|
||||
(single writer at iteration close — the same role that already owns uniform
|
||||
merge/close). `workflow/batch/*` branches are NOT claim branches: no
|
||||
`claim.sh` interaction, no assignee; the orchestrator is the only composer.
|
||||
Pilot charter: the decision comment on [org-internal #3731] (scope, opt-in protocol, cap,
|
||||
success criteria) — this skill implements that charter, not the epic's
|
||||
frozen DAG v1 (which covers only the merge-coordinator nodes N-01..04).
|
||||
|
||||
## Applicability: post-hoc composition only (topology B)
|
||||
|
||||
Two batch shapes exist ([org-internal #3731] charter addendum, comment 39347):
|
||||
|
||||
- **Topology A — single-session mono-branch batch**: one session owns every
|
||||
ticket from inception and writes them on ONE branch (instance: PR [org-internal #3861],
|
||||
audit-h1). Hand composition is natural there — do NOT force this skill on
|
||||
it; record the outcome on [org-internal #3731] as a manual-batch datum instead.
|
||||
- **Topology B — parallel workers, post-hoc composition**: workers finish on
|
||||
SEPARATE branches at different times; the orchestrator composes at
|
||||
iteration close. This is the skill's ONLY applicability — cross-branch
|
||||
conflict attribution, lockfile convergence, and composition ordering are
|
||||
exactly the error-prone parts it mechanizes (path-disjoint admission,
|
||||
fail-closed attribution, `--convergent` surgery, per-member commit
|
||||
retention for revert granularity).
|
||||
|
||||
Quick discriminator: if every "member" would be a commit on a branch you are
|
||||
already writing, that is topology A — keep going, skip this skill. If you
|
||||
are landing OTHER workers' branches you never owned, that is topology B —
|
||||
this skill applies.
|
||||
|
||||
## Preconditions (all mandatory, fail-closed)
|
||||
|
||||
1. **Pilot opt-in**: the epic runs in batch-landing mode — its workers were
|
||||
seeded to report `status=done branch=<ref>` WITHOUT opening PRs (see the
|
||||
pilot note in `headless-session-ops/reference/completion-report.md`).
|
||||
Non-pilot epics keep the per-task 1:1 PR flow.
|
||||
2. **Every member is done**: review-code PASS on its own branch, run bundle
|
||||
archived (`gen-run-bundle.ts --slug <slug> --ticket <N>` — the bundle is
|
||||
committed on the member branch, so composition carries it; the
|
||||
merge-gate's presence check is per close-ref and expects it).
|
||||
3. **2..7 members** — a single done task rides its own 1:1 PR; more than 7
|
||||
(`batch-compose --max-members`, the pilot cap) splits into multiple
|
||||
batches along the path-overlap report.
|
||||
4. **No fast-lane cargo**: prod hotfixes and CI-infra fixes bypass batching
|
||||
entirely (1:1 PR, land immediately) — batching latency must never gate
|
||||
urgent work.
|
||||
|
||||
## Procedure
|
||||
|
||||
### 1. Compose (deterministic core)
|
||||
|
||||
```bash
|
||||
bun .gitea/scripts/batch-compose.ts \
|
||||
--branch workflow/task/<a> --branch workflow/task/<b> … \
|
||||
--out workflow/batch/<epic-slug>-iter<N> --dry-run
|
||||
```
|
||||
|
||||
For batches whose members ALL rewrite a regenerable shared file — the
|
||||
rule, not the exception, for dependency-bump batches (every `bun install`
|
||||
rewrites the root `bun.lock`) — pass `--convergent bun.lock`: the file is
|
||||
exempt from the overlap admission, and a merge that conflicts ONLY on it is
|
||||
surgically resolved to the running head's version (dropped from the index
|
||||
outright when the head no longer carries the path), with the JSON
|
||||
reporting `converged: ["bun.lock"]` and a regeneration hint. A conflict
|
||||
report carrying shapes the tool cannot attribute (rename/delete etc.)
|
||||
fails CLOSED — convergent exemption never widens into a blind pass.
|
||||
|
||||
Exit codes / handling: `1 usage / no-changes-over-base` → drop the named
|
||||
member or fix the invocation; `3 path-overlap` → split the batch along the
|
||||
reported pairs (or land the overlapping member 1:1) and re-run per group;
|
||||
`4 merge conflict` / `5 transport/git error` → fall
|
||||
back to 1:1 for this batch; `0` → drop `--dry-run`
|
||||
and push the composed branch. The script never touches the worktree or
|
||||
index (keeper-style plumbing) and each member keeps its original commits —
|
||||
revert granularity stays per-task.
|
||||
|
||||
### 2. Pre-validate locally (never enter CI red)
|
||||
|
||||
```bash
|
||||
git fetch origin workflow/batch/<slug>
|
||||
git switch --detach origin/workflow/batch/<slug>
|
||||
cd packages/octopus && bun run test:changed
|
||||
cd ../.. && git switch - # back to the orchestrator branch
|
||||
```
|
||||
|
||||
If the compose output carried a `regenerate convergent files (…)` hint —
|
||||
regenerate them FIRST, on the detached batch branch, and push the result
|
||||
(the composed branch deliberately carries a stale convergent file: either
|
||||
the surgically-resolved running-head version, or a member's clean-merged
|
||||
one; either way it is deterministic only after regeneration):
|
||||
|
||||
```bash
|
||||
git switch --detach origin/workflow/batch/<slug>
|
||||
bun install # regenerates bun.lock
|
||||
git add bun.lock # NEVER `commit -am` here: -a stages the
|
||||
# worktree's symlink stubs and trips the
|
||||
# pre-commit symlink guard (core.symlinks=false)
|
||||
git commit -m "[<epic-slug>][iter-N] chore(deps): regenerate bun.lock for batch <slug>"
|
||||
git push origin HEAD:refs/heads/workflow/batch/<slug>
|
||||
```
|
||||
|
||||
(On detached HEAD the commit-msg hook's format check is inert — the
|
||||
`[slug][iter-N]` prefix above keeps the corpus contract anyway.)
|
||||
|
||||
Failure → fix on the offending member branch (it is the only place the
|
||||
fault can live — paths are disjoint), re-compose, re-validate. Do NOT push
|
||||
a known-red batch.
|
||||
|
||||
### 3. Open the batch PR (gitea-rest recipes)
|
||||
|
||||
Title: `[<epic-slug>][iter-N] batch: <task-a> / <task-b> / …`
|
||||
|
||||
Body constraints (each is a merge-gate requirement, not style):
|
||||
|
||||
- **English close keywords, one per member issue**: `Closes #A`, `Closes #B`,
|
||||
… — Gitea auto-closes all of them; Chinese 关闭/修复 never auto-close.
|
||||
- **Zero unchecked top-level `- [ ]` lines in the body** — the gate's regex
|
||||
(`^-\s+\[ \]`) blocks on any unindented unchecked box, with no fence
|
||||
stripping. Render deferred/pending items as
|
||||
plain text (`· deferred: …`), never as checkboxes; the per-task live
|
||||
checklists stay on their issues.
|
||||
- Per-member summary (ticket, branch, one line) + bundle index.
|
||||
|
||||
### 4. Paste member syntheses into the PR conversation
|
||||
|
||||
Post one comment per member carrying its review-code verdict block
|
||||
(`**Verdict**: PASS|WARN` + the fenced JSON synthesis, from the member
|
||||
issue's review thread). **Why**: the merge-gate hunts FAIL verdicts only in
|
||||
the PR's own comment stream — a batch PR without these comments passes
|
||||
vacuously (a fake-green hole). Pasting restores FAIL visibility; a member
|
||||
synthesis of FAIL blocks the gate exactly as a 1:1 PR's would.
|
||||
|
||||
### 5. One review-code pass on the batch head
|
||||
|
||||
Run review-code against the batch PR. Members already PASS'd individually —
|
||||
scope the review delta to what composition added (merge seams, cross-member
|
||||
integration the per-task reviews could not see). This posts the required
|
||||
per-sha `pipeline/review-code` status; member statuses do NOT transfer to
|
||||
the composed head.
|
||||
|
||||
### 6. Label and hand off
|
||||
|
||||
Label the PR `ready-to-merge`. From here the flow is stock: the merge
|
||||
coordinator's double-green queue serially merges (CI/check +
|
||||
pipeline/merge-gate on the batch head, bot approve, main-account merge).
|
||||
Do NOT hand-merge, do NOT hand-sync main into the batch branch.
|
||||
|
||||
### 7. Post-merge expectations
|
||||
|
||||
Member issues auto-close via the English keywords; their `## 当前状态`
|
||||
PR/代码评审/CI rows fan out to EVERY close ref (status-sync poller Wide
|
||||
behavior — requires [org-internal #3867], merged 2026-08-31). `task done ≡ PR merged`
|
||||
still holds, transitively
|
||||
through the batch PR; verify milestones fire unchanged.
|
||||
|
||||
## Fallback matrix
|
||||
|
||||
| Failure | Action |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| path-overlap (exit 3) | split batch along overlap pairs / 1:1 for the odd member |
|
||||
| merge conflict (exit 4) | 1:1 for the whole batch |
|
||||
| local pre-validation red | fix on the offending member, re-compose |
|
||||
| batch CI red after mergeable | coordinator dequeues with trail; fix on member branches, re-compose as a new batch PR |
|
||||
|
||||
Any fallback preserves today's behavior — batch landing is an optimization,
|
||||
never a dependency.
|
||||
|
||||
## Measurement (pilot duty — revised per [org-internal #3731] charter addendum 39347)
|
||||
|
||||
Per-iteration attribution only; the global 7-day ratio is trend context,
|
||||
never a pass/fail judge (same-window confounders: test-slim [org-internal #3855] /
|
||||
test-dedupe [org-internal #3854] / the pilot's own PRs). On the server,
|
||||
`bun .gitea/scripts/ci-run-stats.ts --days 7 --json /tmp/<slug>-ci-stats.json`
|
||||
(the `--json` flag takes a filename — bare, it is a silent no-op; the human
|
||||
summary still prints). Same methodology as the checklist-merge-gate.yml
|
||||
2026-08-27 note. Record on [org-internal #3731]: (a) this batch iteration's per-workflow
|
||||
trigger counts vs a historically similar 1:1 iteration, and (b) one
|
||||
fallback drill (construct a path-overlap group → exit-3 split executed).
|
||||
Baseline, trend only: 2026-08-31, 5,081 runs / TOTAL 2.75x single runner.
|
||||
Reference in New Issue
Block a user