/nd: next ai:design PR to rule on — next_design tool + command - #226
Conversation
next_design MCP tool on the human profile, mirroring next_ready's discipline: typed result off the shared label-search enumeration (org scope, archived repos withheld, human overrides excluded), limit refused out of range rather than clamped, oldest-question-first FIFO keyed by the trusted raising comment (vetter 'Reviewed <sha>: design' or producer 'Design-question:', author-gated, most-recent-wins), the question carried whole with noteTruncated, per-field byte caps under the one compile-checked budget. plugins/human-fsm/commands/nd.md modeled on nr.md/ncc.md: same LIMIT convention and refusal relay, second-opinion posture over the raised question (genuine / already-answered / misrouted), exit described against the #219 post-state — an answered design question routes the PR back to the producer as ai:reject + the answer as the work order, one call. Plugin 0.11.0 -> 0.12.0 in lockstep with the marketplace listing; human-profile doc surfaces updated to the three-inbox shape. Closes #220 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 26 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 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
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. Comment |
…n flight Three open PRs bump human-fsm from 0.11.0 and two of them claimed 0.12.0. `/plugin` detects an update by comparing version STRINGS, so the second of a duplicate pair to land serves new content under a version installers have already seen — the stale-content bug the version-hygiene gate exists to catch. Claims are now distinct and monotonic in merge order: #224 (0.12.0), #227 (0.13.0), this (0.14.0). This PR merges last of the three; landing it earlier means re-bumping past whatever main then carries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review found the archived-repo withholding pinned by NOTHING for this lane: `every_org_wide_enumeration_withholds_archived_repos` builds its population by scanning for `org_owner_args()`, and `next_design_fetch` reaches the org scope through `design_open_prs_args`, so the fetch is invisible to that scan and the exemption added beside `flagged_subjects_args` was an unbacked claim. Deleting the withholding left the whole suite green. - `nd_population` is now a named pure function with its own behavior test (the ncc_population shape), so the filter's DELETION fails a test rather than passing silently; - the exemption is backed by two positive pins beside the `flagged_open_subjects` one: the fetch READS the archived set, and the fetch APPLIES the filter; - `nd_hit_class` replaces the filter chain, so every withholding has a NAME: draft (listed, with its own justification — a draft's question is answerable, the code under it is not settled), human-ruled, and unaddressable (the class a bare `excluded` count made invisible); - counts are a PARTITION of aiDesign, asserted as arithmetic; - the array-tail contract is pinned by a fixture whose timestamps disagree with its array order. nd.md bounds the already-answered finding to the surfaces the grant can actually reach and requires a recalled precedent to be marked unverified. READMEs: the three-inbox sweep finished, a next_design ordering section added, and the #206 count enumeration extended. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…amed The mutation pass found one survivor: dropping the withheld-list push for a draft, keeping the count, left the suite green. The push lived only inside `next_design_fetch`, which no unit test can reach, so 'counted' and 'counted and listed by name' were indistinguishable to the suite — while to a human they are a row they can act on versus a number they cannot. `nd_apply_hit` is that fold, split out on the `apply_outcome` precedent, and tested: draft and unaddressable are counted AND named, human-ruled is counted and deliberately not (a ruled subject is a decision made, not an inbox item), a candidate is neither. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…) into /nd Conflicts, and how each resolved: - `.claude-plugin/marketplace.json` + `plugins/human-fsm/.claude-plugin/plugin.json` — both sides bumped the plugin. OURS: 0.14.0 stays, distinct from and above main's 0.12.0 (#224) and the 0.13.0 #227 still claims, and the description keeps the third read. - `plugins/human-fsm/README.md` — the whole command table. MAIN's table taken wholesale, because #224 rewrote the `/design` row and resolving toward ours would restore the `human:design` / `--park` prose #219 deleted; the `/nd` row is spliced back into it. Both intents, main's row verbatim. Everything else auto-merged. Main's deletions stand: nothing here reintroduces `human:design` or `ai:blocked-deploy` in any spelling — every remaining mention in the tree is main's own assertion that the deleted state is inert. nd.md needed no correction against merged main: it describes the post-#219 exit (`ai:reject` with the answer as the trusted work order, one call at the head anchor, no parked spelling), and `human-rule … design --rework` now does exactly that. What was aspirational when written is now what the code does. Coverage rather than hand-verification, per the standing call — two hand-written totals near the merged region are now DERIVED from their fixtures: - the withheld-overflow expectation is `raised - ND_MAX_WITHHELD` off a fixture sized from the cap, not a literal `2`; - the row and envelope digit reserves count their numeric fields from the emitted document (`numeric_fields`) instead of a number typed in a comment. That is the exact shape that survives review and breaks on a merge: a count key added on one branch and a reserve typed on another are each correct alone and conflict with nothing when both land. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
#227 landed `next_leak` / `/nm` in exactly the seams `/nd` occupies, so every conflict was the same shape: main's next_leak against this branch's next_design, two independent siblings. Union throughout — nothing of either side is dropped. 18 hunks in main.rs, resolved by taking main's file whole and re-applying this branch's next_design work onto it: a blunt union spliced the two test modules into each other (mismatched delimiters), because the conflict boundaries cut through shared helper context rather than between the modules. What the markers did NOT point at, and the suite did: - `tools.len()` and the narrowing-tool count. BOTH branches bumped 20 -> 21 and 5 -> 6, so git took the identical literal with no conflict at all — and the merged surface has 22 tools and 7 narrowing ones. A hand-written total, individually correct on each side, wrong once both land. - the `nd_population` / archived-set conformance pins landed inside #227's new test at the end of the same module, where `reads` is not in scope. - the shipped-command list is SORTED: the union had to place "nd" before "nm". Versions: 0.14.0 stays — distinct from and above main's 0.13.0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed e507174: approve — read the diff and verified the merge independently. |
Main added two MCP tools and their commands; this branch changes no tool surface, so main's tool table, command lists, plugin manifest and the counts that measure them (22 tools, 7 narrowing) carry over untouched. The one conflict is `lanes_doc_emits_every_state_with_the_right_members`, where both sides replaced the same hand-written totals for the same reason — a literal that is right on each side of a merge and wrong once both land. Main's is the more general mechanism: each fixture row carries its own expected `(lane, state)` and every total is counted off those annotations, so it is kept and used throughout. This branch's two semantic claims are applied on top of it: - the `leak` bucket emits NO lane cell (#130 clarification 2) — its inventory is the top-level `leaks` array, which is what its descriptor declares as its occupancy. Row #14 is therefore annotated `NO_LANE`, the same hand-off #7 already had, and the retirement is asserted both ways: the annotations expect no `leak` cell, and the emitted doc has no `leak` key at all; - the un-vetted total keeps its second, independent reading off the `DELETED_STATE_LABELS` registry beside main's annotation count. The annotations say where each PR lands; the registry says why the bucket is that size, so deleting a state without retiring its label fails here instead of quietly re-annotating itself. `next_leak` is unaffected by the retired lane cell: it builds its rows from `producer_pr_inventory` through `is_leak_candidate` and `classify_lane`, never from `lanes_doc` — which is the property #222's own test pins. The cross-lane total is now counted off the `NO_LANE` annotations rather than written as `prs.len() - 2`, because that subtraction is exactly the shape that survives a merge silently while the fixture hands off a different number. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes #220
/nd— the nextai:designPR for the human to rule on, third sibling of/nrand/ncc.next_designMCP tool (pr-review-report-rs/src/main.rs)Mirrors
next_ready's discipline exactly, withnext_close_candidate's ordering argument where it transfers:gh search prs --label+org_owner_args()shapepresentable_queueuses (never a checks qualifier — the measured 93-vs-203 lesson), archived repos withheld before the per-PR fetch and counted (next_close_candidate offers flags from archived repos, where no ruling can be written #206), drafts andhuman:*-overridden PRs excluded through the samehas_human_overridepredicate theai:readyqueue reads.limitrefused out of range rather than clamped (next_design_limit, 1..=3, default 1), same wording shape asnext_ready_limit.design_order_key: raising-comment timestamp, ties broken by PR ref) —flag_order_key's FIFO argument transfers whole: no cost signal exists, and the label parks the PR outside every AI actor's queue, so FIFO bounds the limbo.record-verdict designnote (Reviewed <sha>: design, close-candidate twin excluded by its own token) or the producer'sflag-designnote (Design-question:), most-recent-wins, author-gated throughtrusted_commentsso a spoofed marker raises nothing.question.sourceis the typed discriminant; a vetter-raised question reportssha/atHead, a producer-raised one reports null rather than a bool asserting a comparison nothing performed.noteTruncated(note/noteBytes/noteTruncatedat a 2,600-byte cap), with the full per-field byte-cap + compile-time budget guarantee both siblings carry (ND_*constants,const _: () = assert!(...)).counts.noQuestion+ a capped list for labelled PRs with no trusted raising comment (the design twin ofCcGate::NoFlag),fetchErrorslikewise.Wired through the same seams as the siblings:
McpProfile::Humantool list,mcp_all_toolsentry (narrows: limit),McpCall::NextDesign,validate_call,mcp_exec,minimal_args, and the pinned counts (21 tools, six narrowing).plugins/human-fsm/commands/nd.mdModeled on nr.md/ncc.md — same register, LIMIT convention, refusal-relay language, typed-reads/no-shell contract, and second-opinion posture. The raised question is a claim to check (issue → diff → tree via
pr_context/pr_checkout), with three findings, each a different deliverable: a genuine question (presented with the code-constrained option space and a recommendation), already answered (the pointer IS the finding), or misrouted (stated with what the correct state would have been).Written against the post-#219 state (#219, ruled): the exit it points at is the design ruling that routes the PR immediately back to the producer as
ai:reject+ the answer as the trusted work order, one call.human:designand every park spelling appear nowhere in it.Grant pinned by test (
nd_grants_the_queue_the_pr_the_source_and_the_lens):next_design,pr_context,pr_checkout,clone_release+Skill,Read.Plugin release
plugins/human-fsm/.claude-plugin/plugin.jsonand.claude-plugin/marketplace.jsonbumped 0.11.0 → 0.14.0 in lockstep; descriptions now name the third read. The three doc surfaces listing the human profile (CLAUDE.md, README.md, plugins/human-fsm/README.md) updated to the three-inbox shape.Version coordination — this PR should merge LAST of the three human-fsm bumps in flight. Three open PRs bump the plugin from 0.11.0, and two cannot ship one version string:
/plugindetects updates by comparing version STRINGS, so the second to land under a duplicate version would serve new content under a version installers have already seen. The claims are distinct and monotonic in merge order:human:designdeletion)/nm)If this lands earlier than that order, its version must be re-bumped past whatever
mainthen carries — a lower or equal number against main is the same stale-content bug, and theversion hygienejob's lockstep + bump checks are what catch it.The stronger reason to merge last is SEMANTIC, not the version string. nd.md and the
next_designtool description both describe the post-#219 exit: answering routes the PR back asai:reject+ the work order in one call, with no parked spelling and no waiting state.maindoes not implement that yet — today/designwriteshuman:designand takes--rework | --park. If this PR lands before #224, plugin 0.14.0 ships a command whose stated exit its own ruling command does not perform:/ndwould tell the human the answer sends the PR back to the producer, and/designwould park it under a label the FSM still has. The version ordering is a consequence of that dependency, not the reason for it.Coordination hazard — the
/designrow ofplugins/human-fsm/README.md. #224 rewrites that row (it deletes thehuman:design/--parkprose); this PR reformats the surrounding table and the paragraphs under it. The conflict is guaranteed. 224's version of that row wins — resolving toward this side would restore thehuman:designand--parkprose #219 deleted, which is the exact regression the deletion PR exists to prevent. Take 224's row verbatim; only the/ndrow and the three-inbox prose come from here.Tests
Mirror
next_ready's: limit guard boundaries (default/null/1/max, refusals at 0, max+1, -1, "2", 1.5), row shape for both sources, empty-queue answer, truncation flag, prefix-of-ranked-order paging, adversarial byte-budget page, measured fixed allowances, question-source provenance (spoofed author, adjacent trusted comments, most-recent-wins), and the population query pinned as a value. Conformance:design_open_prs_argsregistered inevery_org_wide_enumeration_withholds_archived_reposas a PURE argv builder whose live caller withholds.Coordination note: based on main; the #219 deletion PR and the #130 stateDescriptors PR are in flight in the same file — this PR touches neither's paths (no
human:designmachinery, no human-queue emission); on conflict, main gets merged in.QA
next_design_tests— the limit guard, the row shape for both question sources, the empty-queue answer, the truncation flag, prefix-of-ranked-order paging, the adversarial byte budget, the measured fixed allowances, the population query as a value, and (added in review)an_archived_repo_hit_is_withheld_from_the_population_and_counted,every_withheld_hit_class_is_named_rather_than_filtered_away,a_withheld_hit_is_both_counted_and_named,the_counts_partition_the_whole_population,the_claim_in_force_is_the_array_tail_not_the_newest_timestamp— plus the extended pins (the_human_profile_is_exactly_read_the_subject_and_rule_on_it,every_shipped_command_carries_its_frontmatter,nd_grants_the_queue_the_pr_the_source_and_the_lens, tool-count/narrows counts, and the two new positive pins insideevery_org_wide_enumeration_withholds_archived_repos). Each fails on base because the functions, the tool and nd.md do not exist there.next_design_fetch:nd_population(...)->(arr.clone(), Vec::new()), i.e. the next_close_candidate offers flags from archived repos, where no ruling can be written #206 withholding deleted -> KILLED byevery_org_wide_enumeration_withholds_archived_repos(this is the mutant that SURVIVED before this round; it is the reason the population filter is now a named, pinned, unit-tested function)nd_populationbody gutted to(hits, Vec::new())-> KILLED byan_archived_repo_hit_is_withheld_from_the_population_and_countednd_apply_hit: draft counted but not pushed to the withheld list -> KILLED bya_withheld_hit_is_both_counted_and_named(survived first pass; the fold was extracted from the network function and tested to kill it)nd_hit_class:has_human_overridearm removed -> KILLED byevery_withheld_hit_class_is_named_rather_than_filtered_awaylast_design_question.next_back()->.next()-> KILLED bythe_claim_in_force_is_the_array_tail_not_the_newest_timestamp+the_question_is_the_most_recent_trusted_raising_commentnext_design_limitout-of-range arm -> clamp instead of refuse -> KILLED bythe_page_size_defaults_to_one_and_is_refused_outside_its_rangenext_design_row"noteTruncated"-> hardcodedfalse-> KILLED byan_oversized_question_is_clipped_and_says_solast_design_question: trusted-author filter dropped -> KILLED bya_spoofed_marker_from_an_untrusted_author_raises_nothingverdict_commentfor the vetter'sReviewed <sha>: design,state_comment("ai:design", …)for the producer'sDesign-question:), so expected note bodies/pins come from the binary's own record format, not from the reader under test; byte-budget expectations come from theND_*cap constants andMCP_MAX_RESULT_BYTES, the same arithmetic the compile-time assert checks; ordering expectations are hand-derived FIFO over explicit timestamps.next_designtool mirroringnext_ready— typed result, refused limit, existing FIFO ordering, question from the trusted raising comment with truncation flagged, shared enumeration: covered; (2)nd.mdon the nr/ncc model with the stated grant, LIMIT convention, three-findings posture, post-RULED: an answered design question routes straight to producer rework, same as a rejection #219 exit: covered; (3) plugin version bump: covered (0.14.0, lockstep with the marketplace listing). Rust tests mirrornext_ready's four named categories (limit guard, row shape, empty queue, truncation): covered.Refs: #219, #130
🤖 Generated with Claude Code