Add mr-skipped outcome to batch mode #259

Open
opened 2026-08-18 02:15:32 +00:00 by david · 0 comments
Owner

Summary

Teach pi-loop's batch mode (src/batch/) to represent and handle the new mr-skipped pipeline outcome as a successful, non-blocking result — batch continuation must not stop or treat "nothing to ship" as a failure.

Background

Depends on: Wire MR-skip outcome into runPipeline

Batch mode processes multiple issues serially in one invocation (npm start -- ISSUE-A ISSUE-B --auto-merge, or --scan --auto-merge). It already has an established pattern for a similar "not a normal MR" outcome: NoCodeChangeOutcome in src/batch/services/batchManifest.ts, detected in buildBatchOutcomes via a 'noCodeChange' in result.pipelineResult check, and handled specially in src/batch/services/runBatch.ts (skips refreshMainAfterMerge, logs a distinct status line, still counts as completed).

This step adds the parallel mr-skipped outcome, mirroring that exact pattern, using the pipeline-result discriminant added in the "Wire MR-skip outcome into runPipeline" step.

Implementation Details

  • src/batch/services/batchManifest.ts:
    • Add the new outcome variant:
      export interface MrSkippedOutcome {
        status: 'mr-skipped';
        reason: 'no-changes';
        runDir: string;
      }
      
    • Add MrSkippedOutcome to the BatchIssueOutcome union (alongside the existing 'completed', NoCodeChangeOutcome, 'failed', 'skipped' members).
    • In validateBatchManifest's validateOutcome function, add a branch accepting status === 'mr-skipped': validate reason equals 'no-changes' and runDir is a non-empty string, mirroring the existing 'no-code-change' branch's validation shape exactly.
    • In buildBatchOutcomes, add a branch (alongside the existing if ('noCodeChange' in result.pipelineResult) check) that detects the mr-skipped pipeline-result shape (from the earlier runPipeline step — check whatever discriminant/field name that step actually used, e.g. mrSkipped on the pipeline result) and emits { status: 'mr-skipped', reason: 'no-changes', runDir: result.runDir ?? '' }.
  • src/batch/services/runBatch.ts:
    • The post-success refreshMainAfterMerge gate (currently if (!('noCodeChange' in pipelineResult)) { ... await refreshMainAfterMerge(...) }) — extend the condition to also skip when the mr-skipped variant is present: if (!('noCodeChange' in pipelineResult) && !('mrSkipped' in pipelineResult)) (adjust the exact property-existence check to match whatever discriminant the runPipeline step actually produced — the point is: no mrResult.branch/targetBranch exists to check out, pull, or delete on the mr-skipped path, exactly as is already true for noCodeChange).
    • The post-success status-line logging — add a branch analogous to the existing 'noCodeChange' in pipelineResult block (which logs something like a "no code changes" status line), logging a distinct line for this case, e.g. `Batch [${issueNumber}/${total}]: ✓ ${ref.provider}:${ref.key} (nothing to ship)`. Match the existing log-line format/style exactly (look at the current noCodeChange status line for the precise template).
    • No changes needed to the working-tree/preflight logic — the next batch item's existing git.isClean + git.pull preflight already handles pulling on an empty feature branch with no divergence correctly (this is an explicit non-change per the feature's design; do not add any extra checkout-to-target step for the mr-skipped case).

Acceptance Criteria

  • validateBatchManifest accepts a manifest containing an 'mr-skipped' outcome entry with valid reason/runDir, and rejects malformed variants (missing reason, wrong reason value, missing/empty runDir) with descriptive errors.
  • buildBatchOutcomes maps a BatchIssueResult whose pipelineResult carries the mr-skipped shape to { status: 'mr-skipped', reason: 'no-changes', runDir }.
  • runBatch never calls refreshMainAfterMerge (or any of its checkout/pull/deleteBranch git-seam calls) for an mr-skipped issue.
  • runBatch logs a distinct, recognizable status line for the mr-skipped case (not the same text as noCodeChange or completed).
  • An mr-skipped issue is counted as completed for batch purposes — it does not stop the batch and is not treated as a failure.
  • Existing noCodeChange/completed/failed batch tests continue to pass unchanged.
  • npm run build and npm run lint pass with no new errors/warnings.

Test Plan

  • batchManifest.test.ts:
    • validateBatchManifest — a manifest containing a well-formed 'mr-skipped' outcome entry validates successfully; entries missing reason or runDir, or with the wrong reason value, fail with descriptive errors.
    • buildBatchOutcomes — a BatchIssueResult whose pipelineResult carries the mr-skipped shape maps to the new outcome variant with the correct runDir.
  • runBatch.test.ts:
    • A pipeline run returning the mr-skipped result — verify the injected git seam's checkout/pull/deleteBranch (used by refreshMainAfterMerge) are never called, the issue's outcome is recorded as completed (not failed), and the distinct mr-skipped status line is logged.
    • Confirm a subsequent issue in the same batch still processes normally after an mr-skipped issue (no state leakage between issues).

Run npm test -- batchManifest runBatch to confirm the updated/new suites pass, then npm test for the full suite to confirm no regressions.

## Summary Teach pi-loop's batch mode (`src/batch/`) to represent and handle the new mr-skipped pipeline outcome as a successful, non-blocking result — batch continuation must not stop or treat "nothing to ship" as a failure. ## Background **Depends on:** Wire MR-skip outcome into runPipeline Batch mode processes multiple issues serially in one invocation (`npm start -- ISSUE-A ISSUE-B --auto-merge`, or `--scan --auto-merge`). It already has an established pattern for a similar "not a normal MR" outcome: `NoCodeChangeOutcome` in `src/batch/services/batchManifest.ts`, detected in `buildBatchOutcomes` via a `'noCodeChange' in result.pipelineResult` check, and handled specially in `src/batch/services/runBatch.ts` (skips `refreshMainAfterMerge`, logs a distinct status line, still counts as `completed`). This step adds the parallel `mr-skipped` outcome, mirroring that exact pattern, using the pipeline-result discriminant added in the "Wire MR-skip outcome into runPipeline" step. ## Implementation Details - `src/batch/services/batchManifest.ts`: - Add the new outcome variant: ```typescript export interface MrSkippedOutcome { status: 'mr-skipped'; reason: 'no-changes'; runDir: string; } ``` - Add `MrSkippedOutcome` to the `BatchIssueOutcome` union (alongside the existing `'completed'`, `NoCodeChangeOutcome`, `'failed'`, `'skipped'` members). - In `validateBatchManifest`'s `validateOutcome` function, add a branch accepting `status === 'mr-skipped'`: validate `reason` equals `'no-changes'` and `runDir` is a non-empty string, mirroring the existing `'no-code-change'` branch's validation shape exactly. - In `buildBatchOutcomes`, add a branch (alongside the existing `if ('noCodeChange' in result.pipelineResult)` check) that detects the mr-skipped pipeline-result shape (from the earlier `runPipeline` step — check whatever discriminant/field name that step actually used, e.g. `mrSkipped` on the pipeline result) and emits `{ status: 'mr-skipped', reason: 'no-changes', runDir: result.runDir ?? '' }`. - `src/batch/services/runBatch.ts`: - The post-success `refreshMainAfterMerge` gate (currently `if (!('noCodeChange' in pipelineResult)) { ... await refreshMainAfterMerge(...) }`) — extend the condition to also skip when the mr-skipped variant is present: `if (!('noCodeChange' in pipelineResult) && !('mrSkipped' in pipelineResult))` (adjust the exact property-existence check to match whatever discriminant the `runPipeline` step actually produced — the point is: no `mrResult.branch`/`targetBranch` exists to check out, pull, or delete on the mr-skipped path, exactly as is already true for `noCodeChange`). - The post-success status-line logging — add a branch analogous to the existing `'noCodeChange' in pipelineResult` block (which logs something like a "no code changes" status line), logging a distinct line for this case, e.g. `` `Batch [${issueNumber}/${total}]: ✓ ${ref.provider}:${ref.key} (nothing to ship)` ``. Match the existing log-line format/style exactly (look at the current `noCodeChange` status line for the precise template). - No changes needed to the working-tree/preflight logic — the next batch item's existing `git.isClean` + `git.pull` preflight already handles pulling on an empty feature branch with no divergence correctly (this is an explicit non-change per the feature's design; do not add any extra checkout-to-target step for the mr-skipped case). ## Acceptance Criteria - [ ] `validateBatchManifest` accepts a manifest containing an `'mr-skipped'` outcome entry with valid `reason`/`runDir`, and rejects malformed variants (missing `reason`, wrong `reason` value, missing/empty `runDir`) with descriptive errors. - [ ] `buildBatchOutcomes` maps a `BatchIssueResult` whose `pipelineResult` carries the mr-skipped shape to `{ status: 'mr-skipped', reason: 'no-changes', runDir }`. - [ ] `runBatch` never calls `refreshMainAfterMerge` (or any of its `checkout`/`pull`/`deleteBranch` git-seam calls) for an mr-skipped issue. - [ ] `runBatch` logs a distinct, recognizable status line for the mr-skipped case (not the same text as `noCodeChange` or `completed`). - [ ] An mr-skipped issue is counted as `completed` for batch purposes — it does not stop the batch and is not treated as a failure. - [ ] Existing `noCodeChange`/`completed`/`failed` batch tests continue to pass unchanged. - [ ] `npm run build` and `npm run lint` pass with no new errors/warnings. ## Test Plan - `batchManifest.test.ts`: - `validateBatchManifest` — a manifest containing a well-formed `'mr-skipped'` outcome entry validates successfully; entries missing `reason` or `runDir`, or with the wrong `reason` value, fail with descriptive errors. - `buildBatchOutcomes` — a `BatchIssueResult` whose `pipelineResult` carries the mr-skipped shape maps to the new outcome variant with the correct `runDir`. - `runBatch.test.ts`: - A pipeline run returning the mr-skipped result — verify the injected `git` seam's `checkout`/`pull`/`deleteBranch` (used by `refreshMainAfterMerge`) are never called, the issue's outcome is recorded as completed (not failed), and the distinct mr-skipped status line is logged. - Confirm a subsequent issue in the same batch still processes normally after an mr-skipped issue (no state leakage between issues). Run `npm test -- batchManifest runBatch` to confirm the updated/new suites pass, then `npm test` for the full suite to confirm no regressions.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
david/pi-loop#259
No description provided.