Skip to content

feat(triage): give up on leads that stay unjudgeable (#402) - #410

Merged
MrReasonable merged 3 commits into
mainfrom
fix/unjudgeable-give-up-402
Oct 15, 2026
Merged

MrReasonable merged 3 commits into
mainfrom
fix/unjudgeable-give-up-402

Conversation

@MrReasonable

@MrReasonable MrReasonable commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

Triage re-fetched and re-judged every unjudgeable lead on every run with no end, paying a judge call per lead per night for a page that was never a posting (#402). This adds an opt-in give-up threshold.

  • triage.unjudgeable_give_up_after (int, default 0 = off). At 0 nothing is counted, evicted or skipped. It ships commented in sluice.yaml.example. The validator refuses YAML bools, floats and quoted numbers.
  • Counter: triage_unjudgeable_count on the lead, written in the same compare-and-set update_fields call as the status. It only lands where an unjudgeable write may land (new/unjudgeable). It always carries a require_unchanged, so a count a person types or resets mid-judge is never overwritten. When only the counter's guard refuses, _write_counted retries without it, so the verdict still lands. Any other landed classification or verdict clears it. A result decided on the note's own pasted job description never counts.
  • Fresh fetch per count: a landed judge unjudgeable drops that lead's cached page (DossierCache.forget). get_or_build treats an entry evicted between its freshness check and its read as a miss.
  • Giving up: a lead at unjudgeable with a count at or above the threshold, and no pasted job description, is still classified (free), so a reject rule can still dismiss it. It is not sent to company resolution, not fetched and not judged, and does not use up --limit. It is counted under a new given_up digest row that says how to retry.

Design spec: docs/superpowers/specs/2026-10-14-unjudgeable-give-up-design.md (three /review-plan rounds, ending with no Critical or High findings). Plan: docs/superpowers/plans/2026-10-14-unjudgeable-give-up.md.

Owner decisions (delegated to my recommendations)

  1. Give up after N consecutive unjudgeable results, counted per fetch, not per day.
  2. Eligible again: a pasted job description, a human edit or deletion of the key, or a landed real verdict. A new last_seen (bumped by every ingest), a new URL (never rewritten by ingest) and the dossier ttl were rejected.
  3. The counter lives in a frontmatter key, not the audit log.

Residuals, stated

  • A lead whose block clears after it has given up is never seen to heal, because nothing fetches it again. On one install's frozen snapshot, 0 of 85 unjudgeable leads healed in four weeks.
  • The first count after the setting is turned on can be taken on a page cached before it was on.

Test plan

  • python -m pytest: full suite green locally, including with PATH=/usr/bin:/bin.
  • ruff check sluice tests scripts
  • Mutation witnesses: every condition in the predicate, the split and withhold placement, the counting and clearing CAS, the retry, each eviction condition, the config default and the example-file guard. Each one goes red when deleted or moved.
  • /review-pr: two rounds with five reviewers plus the CodeRabbit CLI. All findings are fixed, including the CLI's never-clobber finding about a count typed into an absent key.

Closes #402

Summary by CodeRabbit

  • New Features

    • Added an optional limit for repeated unjudgeable results. Once the configured threshold is reached, leads are no longer fetched or judged, but remain eligible for classification and reject rules.
    • Added guidance in triage reports on how to retry these leads, including resetting their count or adding a job description.
    • Added reporting for leads that have reached the limit; these leads do not count towards the processing limit.
  • Documentation

    • Updated configuration, usage, architecture and troubleshooting guidance to explain the new setting and its effects.

MrReasonable <4990954+MrReasonable@users.noreply.github.com>
MrReasonable <4990954+MrReasonable@users.noreply.github.com>
New opt-in `triage.unjudgeable_give_up_after` (0, the default, is off). Each
landed `unjudgeable` result, from the pre-judge gate or the judge, adds one to
the lead's `triage_unjudgeable_count` in the same compare-and-set write as the
status; any other landed classification or verdict clears it. A landed judge
`unjudgeable` also drops the lead's cached page (new `DossierCache.forget`), so
every later count is a fresh fetch. Results decided on the note's own pasted
job description never count.

A lead at `unjudgeable` whose count reaches the threshold is still classified
(free, so a reject rule can still dismiss it) but is no longer sent to company
resolution, fetched or judged, does not use up `--limit`, and is counted under a
new `given_up` digest row that says how to retry: delete the key, or paste the
posting under `## Job description`.

MrReasonable <4990954+MrReasonable@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: MrReasonable/sluice/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 86f56ac3-217e-476a-8ac4-bb82b89a230a
📥 Commits

Reviewing files that changed from the base of the PR and between 60e7d6f and e3eb205.

📒 Files selected for processing: 16
  • docs/ARCHITECTURE.md
  • docs/CONFIGURATION.md
  • docs/TROUBLESHOOTING.md
  • docs/USAGE.md
  • docs/superpowers/plans/2026-10-14-unjudgeable-give-up.md
  • docs/superpowers/specs/2026-10-14-unjudgeable-give-up-design.md
  • sluice.yaml.example
  • sluice/cli.py
  • sluice/core/dossier.py
  • sluice/triage/apply.py
  • sluice/triage/config.py
  • sluice/triage/engine.py
  • tests/test_dossier_forget.py
  • tests/test_sluice_neutral_defaults.py
  • tests/test_triage_engine.py
  • tests/test_triage_give_up.py

Included review availability: This review used your included allowance. 4 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.

📝 Walkthrough

The triage workflow now supports a configurable consecutive-unjudgeable threshold. It stores counts on leads, skips eligible leads during fetching and judging, evicts applicable cached dossiers, and reports give-up outcomes with retry guidance.

Changes: Unjudgeable Lead Triage

Layer / File(s) Summary
Configure threshold and persist counters
sluice/triage/config.py, sluice/triage/apply.py, sluice.yaml.example, tests/test_sluice_neutral_defaults.py, tests/test_triage_give_up.py, tests/test_triage_engine.py, docs/CONFIGURATION.md, docs/superpowers/plans/..., docs/superpowers/specs/...
Adds the default-off unjudgeable_give_up_after setting and validates it as a non-negative integer. Guarded writes increment eligible unjudgeable counts or clear positive counts for other outcomes. Tests cover parsing, concurrent edits and write conflicts.
Skip eligible leads and evict judged cache entries
sluice/triage/engine.py, sluice/core/dossier.py, tests/test_triage_give_up.py, tests/test_dossier_forget.py, docs/ARCHITECTURE.md, docs/superpowers/plans/..., docs/superpowers/specs/...
The engine classifies eligible given-up leads without fetching or judging them, and excludes them from the processing limit. It evicts cached dossiers after an applied unjudgeable verdict from a fetched dossier. Tests cover eligibility, cache races and eviction errors.
Report give-up outcomes and document retry options
sluice/cli.py, tests/test_triage_give_up.py, docs/USAGE.md, docs/TROUBLESHOOTING.md, docs/superpowers/plans/..., docs/superpowers/specs/...
CLI output and documentation describe give-up counts, limit handling and how to retry leads by removing the counter or adding a job-description section.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to e3eb2

No issue identified in this review needs to be resolved before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 13.40% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 97 functions across 9 files. (7 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: adding opt-in handling for leads that remain unjudgeable.
Linked Issues check Passed Issue [#402] requires a configurable way to stop repeated unjudgeable judging, with 0 meaning disabled. TriageConfig defines unjudgeable_give_up_after: int = 0, and the loader rejects booleans…
Out of Scope Changes check Passed The changed code, tests and documentation support [#402]. The cache eviction and race handling enable the required per-fetch counting behaviour. The configuration example, CLI output, troubleshooting …
Full details: Docstring Coverage

Explanation

Docstring coverage is 13.40% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 97 functions across 9 files. (7 skipped: 7 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@MrReasonable
MrReasonable merged commit ac48baa into main Oct 15, 2026
12 checks passed
@MrReasonable
MrReasonable deleted the fix/unjudgeable-give-up-402 branch October 15, 2026 02:04
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.

triage: unjudgeable leads are re-judged every run with no give-up rule

1 participant