Skip to content

Close-candidate flags cover both subject types, one upheld inbox, close is decide+do - #215

Merged
thedavidmeister merged 4 commits into
mainfrom
2026-08-05-issue-211-212-cc-flags-cover-prs
Aug 5, 2026
Merged

Close-candidate flags cover both subject types, one upheld inbox, close is decide+do#215
thedavidmeister merged 4 commits into
mainfrom
2026-08-05-issue-211-212-cc-flags-cover-prs

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Closes #211
Closes #212
Closes #213

Three rulings (2026-08-05), one machine:

#211 — flags cover both subject types, and the vetter vets both

  • flagged_subjects_args(noun, state) is the ONE spelling of the label query; the open-side population is now gh search issues and gh search prs (the CLI scopes each noun to one subject type, which is exactly how PR-shaped flags were invisible). Either half failing aborts the read — a queue missing half its population is a falsely-empty queue in partial clothes.
  • closeCandidateUnvetted mixes issues and PRs; record_close_candidate_verdict judges a producer flag on a PR exactly as on an issue, and its reject returns each subject to its own queue (issue → backlog, PR → vet lane). It refuses only the PR whose label is the vetter's own close verdict — no producer claim exists there for a second AI judgement.
  • The PR-side strand guard is the issue guard's twin: a ruling that neither disposes a live flag nor clears its label is refused (ai:* targets dispose structurally via labels_to_remove).
  • next_close_candidate reports coverage on a PR row as not-applicable-subject-is-a-pr (the covering-PRs read is an Issue-type question) and it never blocks.

#212 — one upheld inbox, no PR lane state

  • closeCandidateUpheld is the human's ONE disposal inbox: upheld flags on either subject type plus PRs the vetter verdicted close (CcGate::VetterClose, action skip-vetter-close, queued FIFO by the verdict's own timestamp — the moment the subject became the human's).
  • classify_lane hands every ai:close-candidate PR to the flag machinery (Lane::CloseCandidate, excluded from lanes), below the human-decision arms and above every other ai:* — the same owner precedence cc_gate gives HumanRuled. The closeCandidatePrs counts key is gone; queue.presentable on next_close_candidate is the sum of both human-owned gate states while counts keeps them apart (vetterCloseVerdict).

#213 — a close is decide+do; the retired ruling-state label is gone everywhere

  • No ruling vocabulary offers a close verb (HUMAN_RULING_LABELS 3, HUMAN_PR_RULING_LABELS 2, MCP enums match by derivation); the label is out of the sacred/parked sets, the colour map, the lane emit and both counts keys; the org-wide label definitions are being deleted by hand, so no migration code ships.
  • human-close writes the pinned 👤 human comment, closes, then retires the pending flag — no label at any point. The order is chosen so no tear is invisible, one test per tear point:
    • after the comment, flagged: the torn-close signature (human_close_ruled + open) — cc_gate routes it to CcGate::TornHumanClose and the vetter state-load executes the recorded close (cc_complete_torn_close; counts completedHumanClose / humanCloseCompletionFailed, the close-candidate flags can reach two states with no transition that clears them #179 cleared/clear_failures posture);
    • after the close: a closed subject still flagged — enumerated by the NEW closed-side sweep (sweep_stale_closed_flags: --state closed --label ai:close-candidate, both nouns, archived repos withheld; counts staleClosedFlagsCleared / …ClearFailed / …Archived), which also drains the legacy Add slash commands for the human FSM transitions #94 hand-close residue org-wide; the interactive human-close re-run (StaleFlag) still works;
    • after the comment, unflagged: the re-run resumes it — the comment dedups and the remaining step list is exactly [Close].
  • next_close_candidate counts (never presents) the torn state as counts.tornHumanClose.

Verification

  • Full suite green: 1079 tests, 0 failures; cargo fmt --check clean; clippy adds no new warnings (the one collapsible_match warning pre-exists on main at an untouched line).
  • Scoped mutation pass over the changed behaviour lines (gate arms, search nouns, upheld projection, lane hand-off, step order, plan guards, presentable sum) — transcribed in the QA block below.
  • grep -r "human:close-candidate" over the repo returns only generated human-queue* snapshot data, which the next cron refresh regenerates; the dashboard counterparts are rain-org-health#158/usage-gate: hold the crons 5% BEHIND pace; retire USAGE_SLACK_PCT (refused, not read) #159 (blocked on this landing).

🤖 Generated with Claude Code

QA

  • Discriminating tests: a_pr_close_verdict_is_human_owned_not_stranded_and_not_cleared, a_recorded_close_ruling_dominates_the_flag_lifecycle, the_two_close_candidate_inboxes_search_one_population, cc_item_arrays_are_populated_and_agree_with_their_counts, cc_row_classifies_pr_subjects_through_the_same_gate, classify_lane_maps_every_state_by_precedence, lanes_doc_emits_every_state_with_the_right_members, the_close_follows_the_record_and_labels_are_only_ever_removed, every_tear_point_lands_where_machinery_can_finish_it, the_flag_verdict_judges_a_flagged_pr_and_refuses_the_vetters_own_verdict, a_pr_ruling_that_would_strand_a_live_flag_is_refused, the_close_report_names_the_close_as_well_as_the_ruling, the_envelope_states_what_the_page_left_behind, human_ruling_vocabulary_is_derived_from_the_label_sets — each fails on base: the new ones reference symbols base does not have (compile failure; each also proven discriminating by the mutation column below), the extended ones pin values base emits differently (closeCandidatePrs/humanCloseCandidate keys, 4-entry vocabularies, close-last step order).
  • Mutations applied (probe → killing test; run one-at-a-time against the built suite, tree reverted and verified clean between probes):
    • cc_gate VetterClose arm → NoFlaga_pr_close_verdict_is_human_owned_not_stranded_and_not_cleared
    • cc_gate TornHumanClose arm disabled → a_recorded_close_ruling_dominates_the_flag_lifecycle
    • FLAG_SEARCH_NOUNS["issues","issues"]the_two_close_candidate_inboxes_search_one_population
    • cc_item_arrays upheld filter drops skip-vetter-closecc_item_arrays_are_populated_and_agree_with_their_counts
    • classify_lane flag arm → Lane::VetterVerdictsclassify_lane_maps_every_state_by_precedence
    • human_close_steps close moved after removals → the_close_follows_the_record_and_labels_are_only_ever_removed
    • cc_verdict_plan refuses ALL PRs (flag condition dropped) → the_flag_verdict_judges_a_flagged_pr_and_refuses_the_vetters_own_verdict
    • PR strand guard drops the ai:*-disposes exception → a_pr_ruling_that_would_strand_a_live_flag_is_refused
    • queue.presentable drops the vetter_close term → the_envelope_states_what_the_page_left_behind
    • human_close_ruled matches any Ruled line → every_tear_point_lands_where_machinery_can_finish_it
    • SURVIVED, accepted: next_close_candidate_fetch's TornHumanClose => counts.torn_human_close += 1 mutated to increment presentable — the increment sits inside the network fetch loop, the same untested-wiring class as every other gate-count increment there; the pure envelope test pins the doc shape, not the loop. Disclosed rather than faked with a gh stub the repo does not use.
  • Oracle: the three rulings as filed (Close-candidate vetting misses PR-shaped flags: gh search issues scopes to type:issue #211, /212, /213 including the human:close-candidate splits decide-from-do, a phase no other state models: fuse close rulings into human-close, machinery completes tears #213 refinement + scope comments), the rain-org-health STATES comment that Close-candidate vetting misses PR-shaped flags: gh search issues scopes to type:issue #211 declares to be the spec, gh CLI's type:issue/type:pr search scoping verified live against the org, and the FSM invariants the pre-existing ~1000-test suite already pins.
  • Category check: Close-candidate vetting misses PR-shaped flags: gh search issues scopes to type:issue #211 asks close-candidates on issues AND PRs both be vetted — covered: search (both nouns behind one tested constant), vet gate on both subject types, per-subject reject fallback, PR strand guard, coverage not-applicable on PR rows. Upheld close-candidates are one human inbox: merge closeCandidateUpheld and the vetted-PR lane state #212 asks one upheld inbox and no PR lane state — covered: CcGate::VetterClose into the mixed closeCandidateUpheld, classify_lane hand-off, closeCandidatePrs retired, queue.presentable summing both human-owned states. human:close-candidate splits decide-from-do, a phase no other state models: fuse close rulings into human-close, machinery completes tears #213 (as refined) asks the label gone everywhere, close as decide+do, torn closes self-healed — covered: vocabularies/sacred/parked/colour-map/lane/counts/MCP schemas purged, comment→close→retire order with a test per tear point, TornHumanClose completion plus the closed-side sweep (which also drains the legacy Add slash commands for the human FSM transitions #94 residue); org-wide label-definition deletion is being done by hand per the ruling, so no migration code ships — deliberate, not an omission.

Summary by CodeRabbit

  • New Features

    • Close-candidate review now supports both issues and pull requests.
    • Issues and pull requests share a unified close-candidate workflow and queue.
    • Dashboard views and reporting now include close-candidate counts for both subject types.
  • Updates

    • Human closing is now a single terminal action that records the ruling and closes the subject.
    • Human close decisions no longer add a separate close-candidate label.
    • Close-candidate commands reject items with any existing human ruling.

thedavidmeister and others added 2 commits August 5, 2026 18:02
…se is decide+do

The flag lifecycle is one machine whatever carries the label (#211): the
flagged population is now both gh search nouns behind one argv builder, the
vetter's unvetted inbox and the human's upheld inbox both mix issues and PRs,
and record-close-candidate-verdict judges a producer flag on a PR exactly as
on an issue — refusing only the PR whose label is the vetter's own close
verdict, which lands in the same single upheld inbox (#212) instead of a
PR lane state; classify_lane hands every flagged PR to the flag machinery so
no subject sits in two states at once.

A close ruling is decide+do with no state between (#213): the ruling
vocabularies offer no close verb, human-close writes the pinned comment,
closes, then retires the flag, and every tear lands where machinery finishes
it — an open flagged subject with a recorded close ruling is completed by the
vetter state-load (CcGate::TornHumanClose), a closed subject still flagged is
swept by the same state-load's closed-side search, and an open unflagged one
resumes on re-run via the comment dedup.

Closes #211
Closes #212
Closes #213

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ctor reads the ruling word

FLAG_SEARCH_NOUNS is the single noun list every flagged-population enumerator
iterates (open-side fetch, closed-side sweep, and the tests), so the prs half
cannot silently drop out of one of them; human_close_ruled gains the test that
a recorded keep-open — whose anchor also spells "close-candidate @" — never
reads as a torn close the completion would execute.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@thedavidmeister, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 49 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 198c87a2-a846-4fc5-aa77-c4b7ff843cec

📥 Commits

Reviewing files that changed from the base of the PR and between a5da359 and d86235a.

📒 Files selected for processing (5)
  • .claude-plugin/marketplace.json
  • CLAUDE.md
  • README.md
  • plugins/human-fsm/.claude-plugin/plugin.json
  • plugins/human-fsm/commands/close-candidate.md

Walkthrough

The PR removes human:close-candidate, makes human-close a direct terminal transition, and extends close-candidate vetting, queues, and reporting from issues to both issues and pull requests.

Changes

Unified close-candidate workflow

Layer / File(s) Summary
Direct human-close transition
CLAUDE.md, plugins/human-fsm/commands/close-candidate.md, README.md
Human closing now records the ruling, closes the issue or pull request, and retires ai:close-candidate without adding human:close-candidate.
Mixed issue and pull-request vetting
campaign-prompt.txt, review-prompt.txt, README.md
Close-candidate production, review, context lookup, and verdict recording now support both subject types.
Shared queue reporting
README.md
Close-candidate queues and references now cover both issues and pull requests.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Human
  participant human_close
  participant GitHubSubject
  participant Labels
  Human->>human_close: submit close decision
  human_close->>GitHubSubject: post pinned ruling comment
  human_close->>GitHubSubject: close issue or pull request
  human_close->>Labels: retire ai:close-candidate
Loading

Possibly related issues

  • rainlanguage/issue-pr-cron 213: Retires human:close-candidate and consolidates closing into human-close.
  • rainlanguage/issue-pr-cron 211: Extends close-candidate vetting and reporting to issues and pull requests.
  • rainlanguage/issue-pr-cron 72: Covers the expanded issue and pull-request close-candidate vetting workflow.
  • rainlanguage/issue-pr-cron 212: Unifies issue and pull-request close-candidate queues and human transitions.
  • rainlanguage/issue-pr-cron 73: Covers the combined FSM, vetting, ruling, and queue changes.

Possibly related PRs

Suggested labels: ai:ready

Suggested reviewers: claude

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: unified close-candidate handling across subject types and a combined decide-and-do human close flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-08-05-issue-211-212-cc-flags-cover-prs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/human-fsm/commands/close-candidate.md`:
- Around line 29-35: The close-candidate documentation must distinguish the two
PR cases: update the reject section in
plugins/human-fsm/commands/close-candidate.md (lines 29-35) to document
producer-flag PRs being rejected to unvetted and vetter-owned PR close verdicts
being sent to human-close, including both commands; update the adjacent
population invariant in CLAUDE.md (lines 359-370) to make the same distinction
between producer flags and vetter-owned close verdicts.

In `@README.md`:
- Around line 117-122: The transition documentation for human-close currently
lists the operations in the wrong order. Update the human-close row in README.md
and the matching transition table in CLAUDE.md to document ruling comment,
close, then retirement of ai:close-candidate, matching the terminal-edge
recovery model.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d196dbb8-bafd-42e7-88f8-a482cb2a644b

📥 Commits

Reviewing files that changed from the base of the PR and between 744fd64 and a5da359.

📒 Files selected for processing (6)
  • CLAUDE.md
  • README.md
  • campaign-prompt.txt
  • plugins/human-fsm/commands/close-candidate.md
  • pr-review-report-rs/src/main.rs
  • review-prompt.txt

Comment thread plugins/human-fsm/commands/close-candidate.md Outdated
Comment thread README.md Outdated
thedavidmeister and others added 2 commits August 5, 2026 18:19
The three markdown files this branch edited take the denofmt reflow the
rainix pre-commit bundle enforces, and the plugin content change is a
release: plugin.json and the marketplace entry move to 0.11.0 together.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The human-close rows in both transition tables now state comment -> close ->
retire (the order the machinery is built around), and the reject/population
prose distinguishes a producer flag on a PR (judgeable; reject returns it to
the vet queue) from the vetter's own close verdict (the human's, refused by
the flag verdict) instead of collapsing the two PR cases into one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thedavidmeister

Copy link
Copy Markdown
Contributor Author

Reviewed d86235a: ready to merge.

Independent read of the head tree, not the report: vocabularies carry no close verb (HUMAN_RULING_LABELS=[reject,design,keep-open], PR twin=[ai:reject,human:design]); human_close_steps = comment → close → retire, already-ruled dedup collapses to bare close; cc_gate precedence is writability → human label ruling → torn-close completion → flag lifecycle, shared by vetter state-load and /ncc (one classifier, #179 property held); torn-close detector reads trusted 👤 ruling lines only, keep-open near-collision pinned by test; a later human:* re-ruling DOMINATES a stale torn-close comment (fail-safe: no auto-close against a standing human label); flagged PRs leave the lanes via the CloseCandidate hand-off below the human arms (no double inventory, owner agreement with cc_gate); sweep_stale_closed_flags covers the close→retire tear on both nouns, archived withheld and counted, failures surfaced as rows, search failure non-fatal by design; zero occurrences of the retired label repo-wide including snapshots. Mutation pass: 10/11 killed, the accepted ncc fetch-loop survivor is disclosed in the QA block and is network-loop wiring per repo convention.

@thedavidmeister
thedavidmeister merged commit 3a825fd into main Aug 5, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment