diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fd59954b..9e986bf9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **/ship now reviews in proportion to what the diff can break: light, standard or full depth.** A diff with 50 or fewer runtime lines gets one batched specialist plus the native adversarial pass, a larger runtime diff gets the class's specialists scoped to their hunks, and gate code or any classifier error gets the full review as before. The receipt records the depth and the queue refuses a receipt below what the head needs. Before this, a 12-line fix paid for the same reviewer fan-out as a change to the merge gate. The backtest that would have let light depth drop the adversarial pass was inconclusive (9 light-eligible PRs, 5 with attributable findings, below the 15 the plan required), so light keeps it. ### Added -- **Review depth** (`lib/review-depth.ts`, `lib/review-collect.ts`, `gstack-review-plan`): `REVIEW_DEPTH:` (depth, runtime lines, the rules hash, reasons), `GATE_SCAN:` bound to HEAD, one `DEPTH_ERROR:` per input that fails closed to full (with the input, the cause and the repair), and per-reviewer `DIFF_CMD:` pathspecs. Runtime lines leave out docs, tests and outputs registered with a command in the base branch's `.gstack/generated.json`, read at the base commit. `--depth-floor standard|full` only raises the depth. A fixed blocker or a CRITICAL raises light to standard for the rest of the invocation. +- **Review depth** (`lib/review-depth.ts`, `lib/review-collect.ts`, `gstack-review-plan`): `REVIEW_DEPTH:` (depth, runtime lines, the rules hash, reasons), `GATE_SCAN:` bound to HEAD, one `DEPTH_ERROR:` per input that fails closed to full (with the input, the cause and the repair), and per-reviewer `DIFF_CMD:` pathspecs. Runtime lines leave out docs, tests and outputs registered with a command in the base branch's `.gstack/generated.json`, read at the base commit. `--depth-floor standard|full` only raises the depth. A fixed or open blocker, or a CRITICAL, raises light to standard for the rest of the invocation. - **Receipt fields**: `gstack_version` and `review_depth` (`{ depth, class, runtime_lines, rules, base, registry, gate_scan: { tagged, head }, reasons }`), computed at the checked-out head. `write --head` must be HEAD. `review_loop_exception` (`write --review-loop-exception`) records an owner-accepted stop after a fix-check edit with the fix-check's head and findings, and the PR body repeats its line word for word (Fixes #3559). - **Queue checks** (`gstack-ship-queue ready`, `train build`): the depth the head needs is recomputed from git and a lower receipt is `QUEUE_RECEIPT_DEPTH_RAISED`, with the receipt's depth, the required depth, reasons and inputs on a `REVIEW_DEPTH:` line. A malformed owner exception, a body that dropped its line, or a fix-check head that is not the bound head or its ancestor is `QUEUE_RECEIPT_EXCEPTION_INVALID`. The queue reads the same committed range as the writer and trusts a recorded gate scan only when it names the full bound commit. A receipt with neither new field predates depth receipts and is accepted as legacy. diff --git a/docs/ship-policy.md b/docs/ship-policy.md index ad60544a3..bd848b5a2 100644 --- a/docs/ship-policy.md +++ b/docs/ship-policy.md @@ -221,8 +221,11 @@ It refuses (`QUEUE_NOT_READY`) when the working tree has tracked edits, HEAD is not the PR's pushed head, CI at that exact head is not green, or the pregate result is not a current pass, and (`QUEUE_RECEIPT_MISSING`, `QUEUE_RECEIPT_STALE`) when the PR body carries no /ship receipt for that -head: /ship runs before every READY ([details](#ship-before-ready)). Send the -block as printed. +head: /ship runs before every READY ([details](#ship-before-ready)). It also +refuses `QUEUE_RECEIPT_DEPTH_RAISED` when the receipt's review depth is below +what the head needs and `QUEUE_RECEIPT_EXCEPTION_INVALID` when an owner +exception the receipt records does not stand ([the ship receipt](#ship-receipt)). +Send the block as printed. **2. Lane behind another PR: gate ahead.** Gate the tree the queue will have once the predecessor lands, while it is still open: @@ -370,12 +373,17 @@ slot. The queue enforces this at every step from the PR body alone: - `ready` refuses with `QUEUE_RECEIPT_MISSING` when the body has no valid receipt and with `QUEUE_RECEIPT_STALE` when the receipt's `head` is not the head being READY'd (or its `pr` is another PR); the informational - `SHIP_RECEIPT:` line still prints. There is no flag around it. + `SHIP_RECEIPT:` line still prints. It refuses `QUEUE_RECEIPT_DEPTH_RAISED` + (with a `REVIEW_DEPTH:` line) when the receipt records a review depth below + what the head needs, and `QUEUE_RECEIPT_EXCEPTION_INVALID` when an owner + exception it records does not stand ([the ship receipt](#ship-receipt)). + There is no flag around it. - `train build` refuses a pin whose PR has no current receipt with the same codes, naming the PR, before anything is written, pushed or dispatched, `--dry-run` included. -- `verify --train` refuses the slot with the same codes before printing - `MERGE_CONDITION`. +- `verify --train` refuses the slot with `QUEUE_RECEIPT_MISSING` or + `QUEUE_RECEIPT_STALE` before printing `MERGE_CONDITION`; it does not + recompute the review depth. **The stamp keeps the pin's receipt.** The slot's stamp commit changes only stamp files (and, from slot 2 on, merges main into the pin), so no /ship runs @@ -478,6 +486,9 @@ its record. Refusals, all before any spend: `QUEUE_TRAIN_UNTRUSTED` (a fork head), `QUEUE_TRAIN_MOVED` (a head moved from its pin), `QUEUE_RECEIPT_MISSING` and `QUEUE_RECEIPT_STALE` (the PR body has no /ship receipt for the pin; see [/ship before READY](#ship-before-ready)), +`QUEUE_RECEIPT_DEPTH_RAISED` and `QUEUE_RECEIPT_EXCEPTION_INVALID` (the +receipt's review depth is below what the pin needs, or an owner exception it +records does not stand; see [the ship receipt](#ship-receipt)), `QUEUE_NOT_READY` (no READY receipt at that head), `QUEUE_TRAIN_CONFLICT` (the printed `QUEUE_TRAIN_CONFLICT: train stopped at # (conflicts: ) after merging #,#; nothing dispatched, no branch pushed; fix: …` line names @@ -836,7 +847,8 @@ recomputes the depth at the new head, rebinds the gate scan, and refuses when the new head needs a deeper review than the receipt records (a test change that skips a test raises the diff to gate class), when `--head` is not the checked-out HEAD, when the receipt records `gstack_version` without -`review_depth`, or when an owner exception no longer stands. +`review_depth`, or when an owner exception no longer stands, each as +[`RECEIPT_CARRY_REFUSED`](troubleshooting.md#receipt-carry-refused). **`review_loop_exception`.** The owner's acceptance of a stop after a fix-check edit under frozen scope (#3559), from `write --review-loop-exception diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index c5e0520a5..95bb3650a 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -2900,10 +2900,12 @@ for an older PR, write it once by hand with the same command. ### `RECEIPT_INVALID` **Meaning.** The block exists but does not validate against the `ship-receipt` -schema (`gstack-artifact schema ship-receipt`). +schema (`gstack-artifact schema ship-receipt`). `gstack-ship-receipt write` +also refuses with this code, and writes nothing, when `--head` is not the +checked-out HEAD: the receipt binds the tree the review read. **Fix.** Regenerate it with `gstack-ship-receipt write`; never hand-edit the -block. +block. For the `--head` refusal, check out that commit and write there. ### `EXECUTION_UNKNOWN` @@ -4438,7 +4440,8 @@ to fix this: the stamp comes only when the slot is called. ### `QUEUE_RECEIPT_DEPTH_RAISED` **Meaning.** `ready` or `train build` recomputed the review depth the head -needs from git (the range against `origin/`, the base commit's +needs from git (the range against the base ref, `origin/` in `ready` +and `/` in `train build`, the base commit's generated-output registry, and the receipt's gate scan when it names this head) and the receipt's `review_depth.depth` is below it, or the receipt comes from a gstack that records `gstack_version` but carries no `review_depth`. The @@ -4457,8 +4460,10 @@ Never edit `review_depth` by hand ([review-policy.md](review-policy.md#review-de **Meaning.** The receipt records an owner exception (`docs.exception` or `review_loop_exception`) that the queue cannot accept: the record does not parse, a review-loop exception names no fix-check (`review_loop.fix_checks` -is 0 or missing), or the PR body no longer carries the exception's line word -for word (`Documentation exception: …` or `Review-loop exception: …`). +is 0 or missing), its `fix_check.head` is neither the bound head nor an +ancestor of it (not checked after a carry across rewritten history), or the PR +body no longer carries the exception's line word for word +(`Documentation exception: …` or `Review-loop exception: …`). **Fix.** Restore the line in the PR body exactly as `write` printed it, or run /ship again and record the owner's acceptance with `--docs` or @@ -4729,13 +4734,20 @@ untracked changes (a carry certifies a commit, never a tree that differs from it), the receipt's head left HEAD's history and the receipt records no tree to compare (a receipt written before `head_tree`, whose head is not in this clone), or git could not compare the two product diffs or read the working -tree's status. The receipt in the body is unchanged and still names the old -head, so `gstack-ship-queue ready` refuses `QUEUE_RECEIPT_STALE`. +tree's status. It also refuses when an owner exception the receipt records +no longer stands, and, for a receipt from a gstack that records review +depth, when HEAD needs a deeper review than the receipt records, `--head` is +not the checked-out HEAD, or the receipt records `gstack_version` without +`review_depth` ([ship-policy.md](ship-policy.md#ship-receipt)). The receipt in +the body is unchanged and still names the old head, so `gstack-ship-queue +ready` refuses `QUEUE_RECEIPT_STALE`. **Fix.** Commit or stash every working-tree change, then rerun `gstack-ship-receipt carry --pr ` at the new head. When the history is already rewritten and the receipt predates `head_tree`, run /ship on the new -head; next time merge the base in instead of rebasing. +head; next time merge the base in instead of rebasing. For a depth or +exception refusal, run /ship on the new head (or check out `--head` and carry +there). ### `REVIEW_LOOP_EXCEPTION_INVALID`