Files

498 lines
28 KiB
Markdown
Raw Permalink Normal View History

> Core 中立版(Increment 6a 改写,原 deferHard verbatim)。编号与条目结构严格不变(C-2 不变量);实例术语按 `core/adapters/TERMINOLOGY.md` 绑定。
# Review Pipeline Phases (Canonical)
This document is the **single source of truth** for the shared Phase A→E
review/audit pipeline flow. Individual review and audit skills bind their own
parameters and reference this doc rather than duplicating the shared mechanics.
**Terminology**: "reviewer" and "auditor" are interchangeable — `audit-process`
legitimately uses "auditor"/"Re-audit" terminology. All generic descriptions
use `{REVIEWER_OR_AUDITOR}`.
**Output model — two findings sinks** ([org-internal #1988] Tier 1 migration): raw per-dimension
reviewer findings have ONE of two sinks, chosen per skill. The **synthesis**
(human gate) and **commit status** are ALWAYS Tier 2 (Gitea) regardless of the
findings sink.
| Sink | Skills | Reviewer writes findings to | Synthesizer reads findings from |
|---|---|---|---|
| `tier1-local` (migrated) | `review-code`, `review-artifact` (live targets: review-dag, audit-process; the roadmap/design-space/plan targets were archived 2026-08-21, [org-internal #3072] phase 3) | `<runs-root>/{slug}/reviews/{stage}/round{N}/findings-{DIMENSION_CODE}.json` (validated by `core/schemas/reviewer-output.schema.json`) | the local finding files (no Gitea call) |
| `tier2-comment` (fallback) | _(none — all targets migrated)_ | Gitea PR/issue comment via `工单评论 API(见 TERMINOLOGY` (Pattern 5) | `工单评论 API(见 TERMINOLOGY` (Pattern 3) |
Migration complete — every review/audit skill now outputs `tier1-local`; the
`tier2-comment` row remains as the documented fallback (boundary rule:
`core/rules/two-tier-artifacts.md`; a skill without `<runs-root>/`
write access falls back to comment-based output unchanged). A `tier1-local`
reviewer additionally
appends an `index.json` row per finding file (Tier 1 manifest, see
`core/templates/runs-layout.md`).
**Tier 2 outputs (always)**: synthesis is posted as a **Gitea PR/issue comment**
with a fenced ` ```json ` block — except for the `audit-process` target, which
has no source issue and posts the synthesis as a **wiki page**
`audit/{date}/round{N}/synthesis` instead (see `review-artifact/SKILL.md` process target
Output Artifacts); status tracking uses **REST commit status**
(`pipeline/{REVIEW_TYPE}` context). The full Gitea output pattern is documented
in `_shared/gitea-write-patterns.md`.
---
## Phase A — Parallel {REVIEWER_OR_AUDITOR_NAME}
**Orchestrator actions**:
0. **Move the source issue to the `review` column** on the Pipeline Stages
board per `_shared/gitea-write-patterns.md` Pattern 7.5. Skip if no
source issue exists. The review stage is a single board column covering
all review targets (DAG single gate / code review / audit-process).
0.5. **Initialize the review-status file** (round 1 only). The Orchestrator
creates `<runs-root>/{slug}/reviews/{stage}/status.json` before dispatching
round 1, with the full schema-required field set
(`core/schemas/review-status.schema.json`): `slug`, `started_at`
(RFC 3339 timestamp), `current_round: 1`, `max_rounds` (per-skill binding —
`review-artifact` = 3, `review-code` = 2 default / 3 high-risk —
`<instance-root>/workflow-routing.yaml` `review.max_rounds`), `converged: false`,
`history: []`. This
step is skipped on rounds ≥ 2 — the file already exists and the Synthesizer
appends to it in Phase B. Initialization is the Orchestrator's sole
responsibility; the Synthesizer never creates the file. The Orchestrator
also appends an `index.json` row for the file (`type` = `review-status`,
`stage` = `{REVIEW_TYPE}`, `produced_by` = `Orchestrator`, `schema` = the
review-status `$id`).
1. **Tool-availability probe** (defense-in-depth, [org-internal #2115] RC1 / [org-internal #2126]). Before
dispatching any {REVIEWER_OR_AUDITOR}, verify reviewers will be able to read
wiki artifacts (requirements / design / plan / prior-review reports). A
reviewer that cannot read its inputs aborts or hallucinates — catch this ONCE
in the Orchestrator instead of letting {DIMENSION_COUNT} parallel subagents
each rediscover the gap:
- **Primary path**: confirm the Gitea REST API is reachable — probe
`GET <gitea-base-url>/api/v1/repos/{owner}/{repo}/wiki/pages` with
`-H "Authorization: token <token>"` (a 200 or 403 response means
reachable; anything else — timeout, connection refused, 5xx — is
unreachable). If reachable → continue to step 2.
- **Fallback path** (when REST is unreachable, e.g. a
cross-repo scenario [org-internal #2115]): verify the **local wiki clone** at
`<wiki-clone-root>/{repo}-wiki/` is readable —
`glob(pattern="*.md", path="<wiki-clone-root>/{repo}-wiki/")`. If the clone
is readable → continue to step 2; reviewers use the local clone (see
`_shared/gitea-read-patterns.md` Pattern 1 fallback note and the "Tool
Availability & Path Resolution" section of this skill).
- **Both unavailable → FAIL FAST**: post a `failure` commit status (state
`"failure"`, context `pipeline/{REVIEW_TYPE}`, description naming the
missing capability) and abort — do NOT enter parallel dispatch. Report the
gap so the environment can be fixed (restore Gitea REST reachability —
token validity, network route — or
populate `<wiki-clone-root>/{repo}-wiki/`).
This probe is belt-and-suspenders: it exists so a future
environment regression (REST unreachable, stale token) fails gracefully
with one clear message instead of N
silent subagent aborts.
2. Post an initial pending commit status via REST:
```
POST /api/v1/repos/Octopus/octopus/statuses/{SHA}
state: "pending"
context: "pipeline/{REVIEW_TYPE}"
description: "Round {N}: {DIMENSION_COUNT} reviewers dispatched"
```
(See `_shared/gitea-write-patterns.md` Pattern 8.)
3. Spawn **all {DIMENSION_COUNT} {REVIEWER_OR_AUDITOR}s in parallel**. Each
receives:
- The standardized prompt with dimension-specific values filled in.
- Agent type: Explorer.
- Permission: Explorer read-only (see
`core/skills/_shared/review-orchestrator-rules.md` — Default
Explorer Permissions).
- Temperature: 0.1 (deterministic output).
4. Wait for all {REVIEWER_OR_AUDITOR}s to complete. Each reviewer writes its
dimension result to the skill's configured findings sink:
- `tier1-local` (e.g. `review-code`, `review-artifact`, `audit-process`): write the JSON to
`<runs-root>/{slug}/reviews/{stage}/round{N}/findings-{DIMENSION_CODE}.json`
(validated by `core/schemas/reviewer-output.schema.json`). The reviewer
is granted scoped write to `<runs-root>/**` (read-only everywhere else —
this emits the reviewer's OWN output, it does not touch the artifact under
review, so it does not violate rule #7 auditor independence).
- `tier2-comment` (fallback): post an issue comment via
`工单评论 API(见 TERMINOLOGY` (Pattern 5, `_shared/gitea-write-patterns.md`)
with a fenced ` ```json ` block on the target PR (pipeline mode) or issue
(standalone mode). The comment is labeled `**{DIMENSION_CODE} review — round {N}**`.
After all reviewers complete, for `tier1-local` the Orchestrator appends one
`index.json` row per finding file (type `review-findings`, stage
`{REVIEW_TYPE}`, produced_by `Reviewer`, schema = the reviewer-output `$id`).
5. If a {REVIEWER_OR_AUDITOR} fails (crash / timeout), retry once. If still
failed, mark that dimension as `UNRESOLVED` in the synthesis and continue.
Record it for deferred retry at the start of the next round.
---
## Phase B — Synthesis (Delegated)
> **Context optimization**: Phase B is delegated to a Synthesizer (Worker) to
> prevent the Orchestrator's context from accumulating N dimension finding
> Read results (up to N × 50KB per round). The Synthesizer reads all dimension
> findings in its own context, posts the synthesis comment + commit status,
> and returns a compact summary (≤ 2KB). The Orchestrator never reads
> dimension findings directly.
**Orchestrator actions**:
1. Fill the synthesis task template
(`core/skills/_shared/synthesis_task.md`) with:
- Round number. A round-1 dispatch carries the template's step-8
"Round-1 only — findings digest" duty (the Synthesizer writes
`round1/findings-summary.md`, consumed verbatim at Phase E — see the
digest bullet in step 3 below); verify it is present in the filled
template.
- Target PR number (pipeline mode) or issue number (standalone mode).
- List of UNRESOLVED dimensions (reviewers that crashed/timed out).
- Commit SHA and review type.
- For `tier1-local` skills (all review/audit): write the filled template to
`<runs-root>/{slug}/reviews/{stage}/round{N}/task-synthesizer.md` (Tier 1
synthesis prompt; append an `index.json` row, type `synthesis-prompt`). The
`/tmp/octopus/` embryo is NOT used — Tier 1 owns the prompt.
- For `tier2-comment` skills: write the filled template to
`/tmp/octopus/synthesis_task_{slug}_round{N}.md` for `prompt_file` use; the
authoritative copy is published as a Gitea wiki page at
`{slug}/reviews/{stage}/round{N}/task-synthesizer`.
2. Dispatch the **Synthesizer** (Worker) via the `task` tool:
- `role`: `Synthesizer`
- `subagent_type`: `worker`
- `prompt_file`: the synthesis-prompt path from step 1 (Tier 1 local path for
`tier1-local` skills; `/tmp/octopus/...` for `tier2-comment` skills)
- `permissions`: read + write + edit + bash + glob + grep (all allow)
- `temperature`: 0.1
- Foreground (the Orchestrator waits for completion).
3. The Synthesizer:
- Reads all dimension findings from the skill's configured sink:
- `tier1-local`: read the finding files at
`<runs-root>/{slug}/reviews/{stage}/round{N}/findings-*.json` (in its
OWN context, not the Orchestrator's — no Gitea call).
- `tier2-comment`: read all dimension comments via `工单评论 API(见 TERMINOLOGY`
(Pattern 3, `_shared/gitea-read-patterns.md`) on the target PR/issue.
- **Post-check finding-id uniqueness (MANDATORY)**: verifies that `id`
values are unique across ALL findings files of the round (including
every `-r{k}` slot file) — the schema's `uniqueItems` does NOT enforce
this. On a duplicate id, keeps both findings, notes the collision in
the digest and marks the affected dimension WARN (per step 1b of
`_shared/synthesis_task.md`).
- Computes synthesis following `core/schemas/synthesis.schema.json`.
- Posts synthesis as a PR/issue comment via `工单评论 API(见 TERMINOLOGY`
(Pattern 5, `_shared/gitea-write-patterns.md`) — markdown summary + fenced
` ```json ` block matching `core/schemas/synthesis.schema.json`. (This
is the Tier 2 human-gate output — it stays on Gitea for both sinks.) For
the `audit-process` target (no source issue), post the synthesis as a wiki
page `audit/{date}/round{N}/synthesis` instead of a PR/issue comment.
- Posts a commit status via REST with context
`pipeline/{REVIEW_TYPE}` (Pattern 8, `_shared/gitea-write-patterns.md`):
`state: "success"` for PASS/WARN, `"failure"` for FAIL.
- Appends one `history[]` entry for this round to the run's review-status
file `<runs-root>/{slug}/reviews/{stage}/status.json` (validated by
`core/schemas/review-status.schema.json`) — `round`,
`overall_verdict`, `blockers`, `majors`, `minors` — the durable per-round
audit history (defined by `core/schemas/review-status.schema.json`
`history[]`; mirrors the audit-process checklist TRC 10.4), and updates
the file's `current_round` to this round number. (The Orchestrator initializes `status.json` before
round 1 — see Phase A step 0.5 — with the full required field set `slug` /
`started_at` / `current_round` / `max_rounds` / `converged` / `history`.
The Synthesizer only appends `history[]` and updates `current_round`; it
never re-creates the file.)
- **Round-1 findings digest (round 1 only)**: for skills whose final report
carries a Round-1 Findings Summary (`review-code` Phase E step 2.55 and
any target adopting the template section), the round-1 Synthesizer is the
PRODUCER of that table: it writes
`<runs-root>/{slug}/reviews/{stage}/round1/findings-summary.md` — the
rendered `## Round-1 Findings Summary` table (columns
`| Dim | Finding ID | Severity | Summary |`, one row per round-1 finding;
Summary = one-line 摘由/root cause) — distilled from the round-1 findings
it just read in its own context (append an `index.json` row, type
`review-synthesis` — Synthesizer-produced synthesis artifacts; the
round-verdict return summary `synthesis-return.md` keeps the generic
worker-report type `other` per
`_shared/worker-report-persistence.md`). This duty is wired into the
Synthesizer's operative prompt as step 8 of
`_shared/synthesis_task.md` ("Round 1 only — findings digest"). The
Orchestrator at Phase E copies this file
verbatim into the final report; it does NOT read the findings JSONs
(step 4 below) — the digest file is the wired producer→consumer path.
- Returns a compact summary (≤ 2KB) with verdict, per-dimension results,
and re-audit targets.
4. The Orchestrator receives the summary and proceeds to Phase C or Phase E
based on `overall_verdict`. The Orchestrator does NOT read dimension
comments or the synthesis comment directly — all decision-relevant data
is in the Synthesizer's return summary.
5. Present the Synthesizer's return summary to the user in chat.
---
## Phase C — {REVISION_ROLE} Revision
If `overall_verdict` is PASS, skip to Phase E.
Otherwise:
**Orchestrator actions**:
1. Prepare the {REVISION_ROLE}'s input as a structured task, published as a
Gitea wiki page at `{slug}/reviews/{stage}/round{N}/task-{ROLE}` (Pattern 1,
`_shared/gitea-write-patterns.md`). For the `audit-process` target, the
process target's Phase Bindings override the wiki namespace to
`audit/{date}/` — publish to `audit/{date}/round{N}/task-{ROLE}` instead
(see `review-artifact/SKILL.md` process target).
This must contain:
- Paths to all files that need revision.
- Reference to the synthesis comment on the PR/issue (posted in Phase B).
- References to the dimensions that have open BLOCKER, MAJOR, or MINOR
findings, via the skill's findings sink:
- `tier1-local`: paths to the Tier 1 finding files
(`<runs-root>/{slug}/reviews/{stage}/round{N}/findings-{DIMENSION_CODE}.json`).
- `tier2-comment`: references to the individual dimension issue comments.
Dimensions whose only findings are INFO are excluded — INFO is
dispositioned at synthesis and never revised (see the "Severity handling —
INFO disposition" rule in Phase D).
- The {REVISION_ROLE} MUST NOT receive the full text of all findings inline —
use finding-file path / comment references only to avoid context explosion.
- Convergence status: blockers/majors remaining vs. previous round.
- **Revision survival ([org-internal #2601]) — primary path**: the task tool's completion
output includes a `task_id`; passing it back resumes the SAME
{REVISION_ROLE} subagent session instead of creating a fresh one. Round 1:
persist the returned `task_id` with the round's working-notes entry (it
must survive round-boundary compaction). Round ≥ 2: dispatch with
`task_id` set to the previous revision round's — the reviser continues
in-session with its prior context. {REVIEWER_OR_AUDITOR}s are NEVER
resumed — per-round freshness is their independence.
- **Revision survival — fallback** (task_id lost to compaction before it
was persisted): for round ≥ 2, include the current
`<runs-root>/{slug}/working-notes.md` content (run narrative memory:
prior decisions, dead ends, earlier reviewer feedback) and a reference to
the previous round's revision summary. State explicitly that this revises
work a prior round already produced — re-derive from upstream artifacts
ONLY when a finding requires it.
2. Spawn the {REVISION_ROLE} (Worker) with revision instructions from
`core/skills/_shared/review-revision-prompt.md`. For round ≥ 2, pass
the previous reviser `task_id` to resume the same session (see Revision
survival above); reviewer/auditor dispatches are always fresh.
---
## Phase D — {REVIEWER_OR_AUDIT_LOOP} Loop
After the {REVISION_ROLE} completes revision:
1. Increment the round counter, and update `current_round` in
`<runs-root>/{slug}/reviews/{stage}/status.json` to match. Post the round
transition as a progress update to the commit status (Pattern 8):
```
state: "pending"
context: "pipeline/{REVIEW_TYPE}"
description: "Round {N+1}: re-reviewing after {REVISION_ROLE} revision"
```
2. Go back to Phase A (spawn a new round against the revised files).
**Convergence criteria** (stop the loop when ANY of these is true):
| Condition | Action |
| -------------------------------------- | ---------------------------------------------- |
| `overall_verdict` = PASS | Stop. Proceed to Phase E. |
| `current_round` > `{MAX_ROUNDS}` | Stop. Proceed to Phase E with final status. |
| No improvement in 2 consecutive rounds | Stop. (Same blocker count AND same major count |
| (compared to 2 rounds ago) | without reduction). Proceed to Phase E. |
| User explicitly approves current state | Stop. Proceed to Phase E. |
**`{MAX_ROUNDS}` binding** (per skill):
- `review-artifact` skill (process target): **3**.
- `review-artifact` skill (`review-dag` single-gate target): **per depth** from
`dag_metrics.review_depth` — D1 ≤2, D2 ≤3, D3 ≤3, D4 ≤4 (D4 reaches round 4,
exceeding the shared `review-artifact` default; the per-depth cap takes precedence —
see `review-artifact/SKILL.md` review-dag Phase D and
`core/schemas/review-status.schema.json`).
- `review-code` skill: **2** default / **3** high-risk (a BLOCKER survived a
round, or the diff touches a frozen cross-session contract) —
`<instance-root>/workflow-routing.yaml` `review.max_rounds` ([org-internal #3567], process-diet
P0b). At budget without convergence: STOP, register the remaining
BLOCKER/MAJOR findings as TD registry rows, verdict FAIL if any BLOCKER
remains else PASS — the debt is carried by those TD registry rows
(see `review-code/SKILL.md` Phase D). This
supersedes the 2026-08-25 [org-internal #3380] calibration (p50=2, p95=5, n=66): the runs
past round 3 are the marathon tail this budget exists to cut; their residue
flows to the TD registry instead of reviewer rounds. Ledger:
`docs/workflow-refactor/thresholds-ledger.md`.
Rationale for `review-artifact` = 3 (evaluated in [org-internal #1969], replacing the prior blanket
default of 5): (1) the Round-3 Escalation Guardrail below already detects
non-convergence at the start of round 3; (2) the INFO-disposition rule below
removes spurious WARN rounds previously caused by non-blocking INFO findings;
(3) the "no improvement in 2 consecutive rounds" stop condition naturally
fires by round 3; (4) the marginal value of rounds 4-5 is low once the
guardrail has fired and they burn reviewer budget. (`review-code` no longer
reaches round 4 — its round budget is 2/3, see the binding above.)
**Provisional, not empirically validated**: the four safeguards make `review-artifact`=3
defensible, but it has no fresh run-data yet. Treat it as a hypothesis to
confirm via the retrospective signal ([org-internal #1834]; gate-trim's landing machinery was
retired, [org-internal #3072] phase 3 — the check is observational, not a trim proposal): if
live `review-artifact` runs frequently hit round 3 still improving yet are
forced to stop at WARN/FAIL, bump it back to 4.
**Severity handling — INFO disposition** (non-blocking, non-revising): INFO
findings are observations/recommendations beyond the checklist. They NEVER
block convergence and NEVER drive a reviser round.
- A dimension whose ONLY open findings are INFO has effective verdict **PASS**
— INFO does not reduce `pass_rate` and does not cause WARN/FAIL (see
orchestrator rule #3). Such a dimension does NOT count against
`overall_verdict`.
- At synthesis, the Synthesizer dispositions EVERY INFO finding as one of:
- `TD-candidate` — actionable observation worth a tech-debt item; record a
suggested REGISTRY ROW (one-line summary + reactivation trigger,
`core/rules/ticket-lifecycle.md`). Actual `TD-NNN` registration is
deferred to the `verify` skill's Phase 5.5 registry filing — a
TD-candidate does NOT open an independent ticket at review time
(consistent with how `review-code` Accepted Risks flow to verify).
- `DISCARDED` — not worth tracking; record a one-line reason.
Dispositions are listed in the synthesis comment (markdown). INFO counts
carry in `info_count` / `infos` for reporting only.
- Phase C reviser task (step 1 above) references ONLY dimensions with open
BLOCKER/MAJOR/MINOR findings. INFO findings are NEVER passed to the
{REVISION_ROLE}.
**Round-3 Escalation Guardrail** (applies to the `review-artifact` skill's
live targets — the process audit target AND the review-dag single-gate
target; the roadmap / design / plan targets were archived 2026-08-21,
[org-internal #3072] phase 3). `review-code` does NOT use this guardrail; it uses its round
budget ([org-internal #3567], see the `{MAX_ROUNDS}` binding above).
At the start of round 3, if the combined blocker+major count is still >50% of
round 1's count, STOP the loop and surface to the user:
> Review not converging: round 1 had {N1} blockers+majors, round 2 still has
> {N2} ({pct}% of round 1). This suggests the artifact under review needs a
> substantive rewrite, not incremental patching. Options:
> (a) Return to upstream — for the `process` audit target, escalate to the
> octopus maintainer for a process-level redesign (the legacy producer skills
> `roadmap` / `requirements-elicitation` / `design` / `plan-iterations` were
> archived 2026-08-21, [org-internal #3072] phase 3 — `<instance-root>/archive/`), then restart this
> review at round 1.
> (b) Continue iterating — accept that more rounds may be needed (capped by
> `{MAX_ROUNDS}`).
Choosing (a) returns control to the upstream skill (or maintainer); the
review's commit status is marked with description `"escalated"` and
`converged: false`.
**Round-4 user-choice escalation point (shared)**: a multi-round review skill
MUST offer the user an explicit choice before entering round 4 — (a) stop the
review and escalate to a human, or (b) continue into round 4 — via the
`question` tool. The guard means "escalate with a choice", NOT "force-stop".
The choice is UNCONDITIONAL at the round-3→4 transition — instance skills may
narrow when an escalation *variant* (e.g. a design-level decision) fires, but
never narrow the choice gate itself. The call MUST be optionized ([org-internal #3378]):
two options — `Stop & escalate to a human` (first, when recommended) /
`Continue into round 4` — with `stage` set to the running skill's stage so
auto-approval applies in autonomous mode; free-text asking is a spec
violation.
Instance: review-dag D4 option-b (`review-artifact/SKILL.md` §"Round-3
Escalation Guardrail interaction") — the sole live instance, its D4 round cap
(≤4) being the only budget that reaches round 4 (`review-code` is capped 2/3,
[org-internal #3567]).
Rationale (retro 2026-08-21 / [org-internal #3050]): unattended late-round loops drift into
review marathons — the choice forces the design-level stall to surface to a
human at round 4 instead of round 6.
**Efficiency optimization**: From round 2 onward ([org-internal #2598]), only spawn
{REVIEWER_OR_AUDITOR}s for dimensions that had FAIL, WARN, or UNRESOLVED in
the previous round. Every 2 rounds, run a full {DIMENSION_COUNT}-reviewer
sweep to catch regressions. From round 2 onward reviewer input is also
delta-scoped: the file list handed to each reviewer covers only the files
changed since the previous round plus their convention-comparison neighbors,
not the round-1 full set.
---
## Phase E — Final Report
**Orchestrator actions**:
1. Write the final report as a Gitea wiki page at
`{slug}/reviews/{stage}/final/report` (Pattern 1,
`_shared/gitea-write-patterns.md`), using the template at
`core/skills/_shared/review-final-report-template.md`. For the
`audit-process` target, write to `audit/{date}/final/report` instead (wiki
namespace override `audit/{date}/`). Also set the lifecycle `converged` flag
in `<runs-root>/{slug}/reviews/{stage}/status.json`: `true` when the final
verdict is PASS (or WARN with no unresolved BLOCKERs), else `false`. This is
the ONLY place `converged` is written — the Orchestrator at Phase E; the
Synthesizer never sets it.
2. Update the `## 工件索引` comment on the source issue per
`_shared/gitea-write-patterns.md` Pattern 10: add/update the
`REVIEW-{stage}` row (位置 = the final report page, 重读 = CORE —
review conclusions are part of the compaction re-read set).
Skip if no source issue exists (Pattern 10 step 1).
2.5. **Inline-ization (skills that bind it)** — when the review target is a
PR and the skill's Phase E binds the inline-comment step (currently
`review-code` only, as its Phase E step 2.56), execute it now: post the
final round's findings as PR inline comments via
`<harness-package>/script/post-inline-comments.ts` (consumer of frozen
contract `shared/review-inline-v1`): noise findings (INFO / DISCARDED /
`WAIVED-{id}`) are never inlined (contract behavior 2), multi-round
posts delete the identity's previous inline comments first (behavior 5),
stale lines degrade to the file's first diff hunk (behavior 4; caveat:
this server build returns HTTP 500 rather than the contract's 422 for
stale lines — TD-611 — so stale items currently surface under `failed`
with `fallback` empty), and partial failures are accounted — never
blocking the verdict (behavior 6) — in the synthesis comment and final
report's `inline: X posted / Y file-level / Z fallback / W failed` line.
Skills whose target has no PR (e.g. `audit-process`) skip this step. The
skill-specific binding (runner invocation, findings paths, identity,
cleanup) is normative in the binding skill's own Phase E section.
3. Post final commit status via REST:
```
POST /api/v1/repos/Octopus/octopus/statuses/{SHA}
state: "success"|"failure"
context: "pipeline/{REVIEW_TYPE}"
description: "Final: {PASS|WARN|FAIL} after {N} rounds — converged: {true|false}"
target_url: "{wiki page link}"
```
3.5. **Gitea approval timing (mandatory when the PR needs a human approval
gate)**: if the flow requests approval from a human reviewer on Gitea,
register the reviewer FIRST via
`POST <gitea-base-url>/api/v1/repos/{owner}/{repo}/pulls/{index}/requested_reviewers`,
wait for the
`REQUEST_REVIEW` registration to be recorded, and only THEN ask the human
to approve. Approving before the reviewer is registered produces
`official: false` on the approval — the gate treats the PR as unapproved
and the approval must be re-done. ([org-internal #1931]: audit R2→R3 re-loop + re-approve,
~30min wasted on exactly this ordering.)
4. Present the final report to the user and obtain approval via the `question`
tool, passing `stage: "{STAGE}"`.
The `question` tool auto-approves per `core/rules/auto-approve.md` (stage `"{STAGE}"`).
Do NOT advance without approval (auto or explicit).
---
## Orchestrator Rules (Mandatory)
See `core/skills/_shared/review-orchestrator-rules.md` for the mandatory
Orchestrator behavior rules. Substitute `{REVISION_ROLE}`: {REVISION_ROLE}.