Skip to content

feat: configurable on_error for ranking stages - #206

Merged
Tgenz1213 merged 5 commits into
mainfrom
feat/200-stage-on-error
Sep 20, 2026
Merged

Tgenz1213 merged 5 commits into
mainfrom
feat/200-stage-on-error

Conversation

@Tgenz1213

Copy link
Copy Markdown
Owner

Summary

Adds a per-stage on_error: skip | fail to the rank and rerank ranking stages, so users can make a check fail when a ranking stage can't complete, and CI can tell an unavailable dependency (exit 6) from an unmet precondition (exit 7). The default is unchanged: a failed stage skips its file and the run exits 0.

Related issue

Closes #200

In scope

  • on_error: skip | fail on rank and rerank; any other value fails at config load (ExitConfig) naming the stage and key.
  • stage.Kind on stage.Error (unavailable, the zero value, or precondition_not_met). Cosine's embedding failure is unavailable; cosine with no embedding provider is precondition_not_met.
  • Under fail, the engine records a StageFailure (stage, file, kind, error), stops that file's remaining stages, and lets other files run.
  • New exit codes: 6 (unavailable) and 7 (precondition not met, wins when both occur).
  • check --format json gains a failures array (omitted when empty, so default output is unchanged); error text goes to stderr.
  • README, CLAUDE.md, and ADRs 0014 and 0022 updated.

Out of scope

  • Other scorers and their on_error defaults (separate tickets under epic: configurable ranking and screening pipeline #196).
  • Candidate-loading errors (for example Postgres unreachable) and the CI truncation warn-open path. Both happen before any stage runs, so they still skip the file and exit 0 regardless of on_error, as ADR 0022 and the CI policy already document.

Architectural notes

Deviations from "identical behavior" and decisions made along the way:

  • Failure codes (6/7) take precedence over drift (4): a check that couldn't complete isn't a clean verdict. Drift found in other files is still printed and included in the JSON count.
  • --update-baseline with a fail failure returns 6 or 7 and does not write the baseline, so a partial snapshot can't replace a good one.
  • Under fail, the error line reads Error: stage <name> failed for <file> (<kind>): <err> and doesn't repeat the action (generating embedding); the underlying error text is included. The skip path's message is unchanged.
  • The precondition_not_met case for cosine ("no embedding provider configured") is unreachable through the real binary, which always builds an embedder. It is covered at unit/engine level; exit 7 has no e2e coverage.
  • Recorded in docs/arch/0022-candidate-scoring-pipeline.md (amended) rather than a new ADR, since it extends that pipeline's error handling.

Follow-ups

None filed.

QA / testing

Verified locally:

  • go test ./... passes (including the e2e suite that builds and runs the mock binary).
  • golangci-lint v2.12.2 in a Linux container: 0 issues (the local Windows binary panics on a go1.27 dependency, so it isn't used).
  • gofmt clean with \r stripped.
  • go test -race in a Linux container for internal/analysis/..., internal/cli/..., internal/config/....
  • Differential run of base (5a6eb82) vs this branch on identical fixtures (no pipeline, pipeline without on_error, drift, embed failure, text and JSON): stdout, stderr and exit codes identical; JSON never gains a failures key. on_error: skip behaves the same as unset. fail: embed failure exits 6, drift plus failure exits 6, --update-baseline plus failure exits 6 with no baseline written.
  • Mutation check on a scratch copy: 19 mutations; the 5 survivors found were closed with the tests in the last commit (precedence over drift, baseline not written, failure ordering, stop-remaining-stages, the 6/7 literals).

Not verified here, needs CI:

  • Full go test -race -cover ./... including the Docker-backed internal/index tests (only the packages above were run under -race).

Checklist

  • Title follows Conventional Commits (feat:, fix:, docs:, refactor:, build(deps):, etc.)
  • All acceptance criteria from the linked issue are met
  • go test -race -cover ./... passes (partial locally; full run left to CI)
  • golangci-lint run --timeout=5m is clean
  • CLAUDE.md updated if this changes build/test commands, adds or renames a top-level package, changes a cross-package interface, or adds a footgun
  • A new ADR added under docs/arch/ if this embodies an architecturally-significant decision (existing ADR 0022 amended instead)
  • Comments follow the 2-line-max, WHY-only convention

🤖 Generated with Claude Code

Tgenz1213 and others added 5 commits September 20, 2026 12:42
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 20, 2026 18:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The implementation is fully reviewed and the only remaining comment is a minor documentation nit.

Review effort: Lite
Findings: None

What changed in this PR

Adds configurable on_error: skip | fail handling for ranking stages, with failure classification, exit codes 6/7, JSON reporting, tests, and documentation updates.

Changes:

  • Validates per-stage error policies.
  • Records and reports stage failures.
  • Updates CLI output, tests, and architecture documentation.
File Summary
test/​e2e_pipeline_test.go Adds end-to-end coverage.
README.md Documents configuration and behavior.
internal/​config/​stage.go Parses and validates on_error.
internal/​config/​pipeline_test.go Tests configuration handling.
internal/​cli/​cli.go Adds exit-code and JSON failure handling.
internal/​cli/​cli_test.go Tests CLI behavior.
internal/​analysis/​stages.go Applies stage failure policies.
internal/​analysis/​stages_test.go Tests stage policies.
internal/​analysis/​stage/​stage.go Defines stage error kinds.
internal/​analysis/​stage/​cosine.go Classifies cosine-stage failures.
internal/​analysis/​stage/​cosine_test.go Tests cosine failure classification.
internal/​analysis/​pipeline_test.go Tests pipeline failure behavior.
internal/​analysis/​engine.go Records and reports stage failures.
docs/​arch/​0022-candidate-scoring-pipeline.md Documents pipeline error handling.
docs/​arch/​0014-json-check-output.md Documents JSON failure output.
CLAUDE.md Updates project guidance.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Tgenz1213
Tgenz1213 merged commit 38b879a into main Sep 20, 2026
8 checks passed
@Tgenz1213
Tgenz1213 deleted the feat/200-stage-on-error branch September 20, 2026 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: configurable on_error for ranking stages

2 participants