Skip to content

ai:blocked-deploy: migrated as a once-off, state deleted - #225

Merged
thedavidmeister merged 5 commits into
mainfrom
2026-08-06-migrate-blocked-deploy
Aug 7, 2026
Merged

thedavidmeister merged 5 commits into
mainfrom
2026-08-06-migrate-blocked-deploy

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Closes #221

What

Two things, in order — and the order is the point.

1. The migration ran, once. The 2026-08-06 ruling in #221 (verbatim: "migrate all the blocked on deploy back to rejected so it can be reworked to fit in the new deployment paradigm") was executed against live GitHub from this branch's earlier build, over the live population of 13 open PRs. Each got ai:reject, a sha-pinned 👤 human ruling comment recording the ruling it executes, and a trusted Rework note carrying the uniform split-release-lifecycle work order. The transcripts below are that once-off's permanent record; the residue is zero and stays zero.

2. The state is deleted. Per the ruling revision recorded at #221 (comment) (verbatim: "a subcommand? i just want this migrated as a once off so we can delete the state entirely"), the tree that merges carries neither the subcommand nor the state:

  • the migrate-blocked-deploy subcommand is gone in full — Cmd variant, dispatch arm, plan/steps/search machinery, its tests. It ran once; machinery for an empty population is dead weight. (The code that ran is in this branch's history — commit 6caefc1 — which is what the transcripts were produced by.)
  • ai:blocked-deploy is deleted from the FSM compiler-first: RETIRED_BLOCKED_DEPLOY_LABEL was deleted and rustc enumerated every consumer — the classify_lane arm, the blockedDeploy counts emission, the human-queue display section, the label_meta row, the next_action parking arm. Grep was used only as the final prose sweep, never to derive the inventory.
  • the label definition is deleted from every repo across the three orgs that carried it (6 repos; zero open PRs were wearing it, so nothing was destroyed) — sweep output below.

What the deletion means behaviorally, and what the new tests pin: the label no longer classifies — it is unmodelled, so a PR wearing it falls through to un-vetted: the vetter absorbs it and the verdict that judges it strips the dead label. (It is not a leak, and an earlier revision of this PR wrongly said so: human_queue_mode buckets every ai:*-labelled PR via ai_state_label and leak-detects only the unlabeled remainder, so producer_commented — the only route to the Leak arm — is always false for a labelled PR. The tests now feed the input the pipeline actually constructs.) Nothing parks or blocks on it (next_action returns the ordinary CI classification, and a deploy-shaped signal still routes to FlagMigration); and counts carries no blockedDeploy key at all — absent, not zero, because a key held at zero is a dashboard box for a state the machine does not have.

#162's live rule is untouched and still stated: a deploy-shaped block (red prod-pin, legacy redeploy marker) is evidence the repo has not migrated to the split release lifecycle, expressed as a typed ai:blocked-on against that migration. flag-blocked-deploy still parses and still refuses, teaching exactly that replacement.

README, the FSM diagram note and the campaign prompt drop the residue/migration prose accordingly. Comments describe current behavior only.

Sibling coordination

At the time of writing, #223 (stateDescriptors), #224, #226 and #227 are all still open, so this PR merges first. main was merged in (never rebased) to pick up the current head.

PR 223 must delete the state on its merge-main, not relocate it. At fb5ad79 it does not merely add a descriptor row — it re-establishes ai:blocked-deploy across nine sites, and following a "drop the row" instruction literally (re-literalising the const so it compiles) lands resurrection mutant #2 from the table above, green. The required move is: delete RETIRED_BLOCKED_DEPLOY_LABEL outright — do not re-literalise it to "ai:blocked-deploy" — and let rustc enumerate the rest, which is the same compiler-first method this PR used. The sites, so none is missed:

  1. const RETIRED_BLOCKED_DEPLOY_LABEL: &str = STATE_BLOCKED_DEPLOY.key; — the redefinition. Delete the constant, do not re-point it.
  2. const STATE_BLOCKED_DEPLOY: StateDescriptor { … } — the whole descriptor, including hist: Some("blockedDeploy"), label: Some("ai:blocked-deploy (retired #162)"), occupancy: StateOccupancy::Lane(Lane::ProducerBlocked) and emit: Emit::WhileOccupied("blockedDeploy").
  3. &STATE_BLOCKED_DEPLOY in STATE_DESCRIPTORS — and the array length drops from 14 to 13.
  4. The relocated counts emission "blockedDeploy": buckets.get(RETIRED_BLOCKED_DEPLOY_LABEL)… in the descriptor-driven counts block (this PR deletes the key entirely — absent, not zero).
  5. Its kept-while-nonzero comment block above that emission.
  6. RETIRED_BLOCKED_DEPLOY_LABEL in the state-label list iterated alongside RETIRED_HUMAN_REJECT_LABEL / RETIRED_STATE_LABEL / STATE_BLOCKED_ON.key / STATE_READY.key.
  7. The doc inventory comment on the state table that names [RETIRED_BLOCKED_DEPLOY_LABEL] among classify_lane's label constants.
  8. The "key": "ai:blocked-deploy" / "hist": "blockedDeploy" / "label": … descriptor-JSON test fixture, and the "ai:blocked-deploy" entry in the expected key list.
  9. The residue["blockedDeploy"] = 13 fixture and the test that asserts the residue row is emitted while occupied (.find(|d| d["key"] == "ai:blocked-deploy")).

The residue that fixture describes is zero on live GitHub and the label definitions are deleted, so nothing there can be occupied again.

Label-definition sweep

Enumerated across all 134 non-archived repos in rainlanguage + cyclofinance + S01-Issuer; 6 defined the label. Open PRs carrying it at sweep time: 0.

pre-sweep: open PRs carrying the label = 0
=== deleting label definitions ===
  rainlanguage/raindex -> deleted
  rainlanguage/rain.dia -> deleted
  rainlanguage/rain.erc4626.words -> deleted
  rainlanguage/rain.flare -> deleted
  rainlanguage/rainlang -> deleted
  rainlanguage/rain.math.float -> deleted

=== post-sweep verify: repos still defining the label ===
remaining definitions: 0

Gates

  • cargo test (full suite, via nix): 1002 passed, 0 failed in the main binary; 78 more across the other targets, all green.
  • CI-exact static gate on the pinned rainix toolchain (github:rainlanguage/rainix/53e96a7…#rust-shell, rustc 1.94.0), changed file touched first: cargo fmt --all -- --checkFMT-OK; cargo clippy --all-targets --all-features -- -D warnings -D clippy::allCLIPPY-OK.
  • nix build .#pr-review-report --print-build-logs → exit 0.
  • pre-commit bundle (rustfmt, denofmt, …) green at commit time.

Adversarial mutation pass (re-scoped to the deletion)

Every mutant resurrects the deleted state in some way — that is what the deletion's tests have to be able to kill. Each was applied to the committed tree, judged by the FULL cargo test suite, then restored from git.

# Mutation (resurrection) Result
1 classify_lane arm returns (ProducerBlocked, "ai:blocked-deploy") again KILLED — fsm_completeness_tests::lanes_doc_emits_every_state_with_the_right_members, infra_down_tests::the_deleted_blocked_deploy_label_classifies_as_nothing, subject_ref_tests::the_deleted_blocked_deploy_state_emits_no_count_key
2 blockedDeploy counts key re-emitted KILLED — subject_ref_tests::the_deleted_blocked_deploy_state_emits_no_count_key
3 next_action parks on the label again KILLED — worklist_tests::modeled_state_label_short_circuits_to_parked
4 label_meta row restored (label re-creatable org-wide) SURVIVED on the first pass → test strengthened in place (commit b4ffc8c), re-run KILLEDinfra_down_tests::the_retired_labels_are_no_longer_destinations
5 label re-added to PRODUCER_STATE_LABELS KILLED — infra_down_tests::the_retired_labels_are_no_longer_destinations, worklist_tests::modeled_state_label_short_circuits_to_parked
6 state_noun answers for it (a transition could name it) KILLED — infra_down_tests::the_retired_labels_are_no_longer_destinations

6/6 killed after the one strengthening; tree restored clean (git status --porcelain empty), baseline suite green at 1002 passed / 0 failed.

The survivor was a real gap and is worth naming: label_meta is what EnsureLabel hands to gh label create --force, so a surviving row is exactly what would let the next caller that named the string re-create the six label definitions this PR deleted. The strengthened assertion compares against an arbitrary unknown label ("no row of its own") rather than literal default bytes, and keeps the deliberate contrast that retired-but-occupied ai:blocked-infra still HAS its row.

QA

  • Discriminating tests: infra_down_tests::the_deleted_blocked_deploy_label_classifies_as_nothing, subject_ref_tests::the_deleted_blocked_deploy_state_emits_no_count_key, infra_down_tests::the_retired_labels_are_no_longer_destinations (extended), worklist_tests::modeled_state_label_short_circuits_to_parked (extended), fsm_completeness_tests::lanes_doc_emits_every_state_with_the_right_members (extended) — each fails on base: on base the label DOES classify as producer-blocked (rather than falling through to un-vetted), DOES emit counts.blockedDeploy, DOES park in next_action, and DOES carry a label_meta row, so every one of these assertions is the negation of base behavior. Verified per-assertion by the mutation table above, which restores each base behavior individually and confirms the kill.
  • Mutations applied: 6, all resurrections of the deleted state — classify_lane arm → 3 tests; counts key → count-key test; next_action park → worklist test; label_meta row → SURVIVED, strengthened, then killed by the retirement test; PRODUCER_STATE_LABELS re-add → 2 tests; state_noun row → retirement test. Full table above; tree restored, baseline re-run green.
  • Oracle: the ruling revision at RULED: migrate the ai:blocked-deploy residue to ai:reject — rework each PR for the split release lifecycle #221 (comment) ("migrated as a once off so we can delete the state entirely"); the RUSTC ERROR SET as the consumer inventory (the constant was deleted first and the compiler enumerated all 5 non-test + 11 test consumers — grep was used only for the final prose sweep); and live GitHub as the end-state oracle for the once-off (residue 0, label definitions 0/134 repos).
  • Category check: ruling asks (a) drop the subcommand entirely, (b) delete the state compiler-first with tests moved to the deletion pins, (c) delete the label definition across the three orgs, (d) README residue prose out with Retire ai:blocked-deploy: deploys never block merges under the split lifecycle — collapse into typed ai:blocked-on refs to the repo's migration #162's live rule kept, (e) sibling coordination, (f) gates + mutation pass + PR body keeping both transcripts; covered (a)-(f) — (e) noted above since 223 is still open, and the earlier once-off transcripts are preserved verbatim below.

Dry-run transcript (live GitHub, report mode)



13 open PR(s) carry the retired ai:blocked-deploy (report only; pass --apply to write)
  [report] rainlanguage/rain.dia#61 @ 6f1b8d666a96afb8fc411bd4b13747e505b03cb7 -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rain.math.float#256 @ 8bc1cf70d01439d7f50e7bd893f01ec0ebb23a69 -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rain.dia#57 @ ea63d0fb13f7b962ae183c2e150b1d5acfe869bb -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rain.math.float#253 @ 865a49e42a4703562a1af899cc90794f6790d55c -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rain.erc4626.words#252 @ 62c782c6c95da52bc30c4ce09fa4e46e2a91fc3a -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rain.math.float#245 @ 0dfd28c7b18c14d9ccc170105f6af5f347bd774a -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/raindex#2779 @ 90b1e5ecaf2a47cc41ee75d4ae7cd737382a18da -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rain.math.float#244 @ 9b0cc58c287f416ef04dbb5597f26256b3050112 -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rain.flare#160 @ 18712ecf512ced42397d33f46c1a9f684b8b3263 -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rainlang#537 @ 23d605015892d5bbc29de677ba6fb2634199a29a -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rainlang#536 @ 655a02b46c65ba0d61b03119dc7ac57236437b5c -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rainlang#534 @ 8af4a51678f28fe1738c2b9f2f716220261ad0bd -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
  [report] rainlanguage/rain.math.float#237 @ 8129870cecba51fc5b8f6954ebe05943cbbac2da -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
would migrate: 13 PR(s), 0 skipped (moot or live flag)

Live execution transcript (--apply)



13 open PR(s) carry the retired ai:blocked-deploy — migrating to ai:reject
https://github.com/rainlanguage/rain.dia/pull/61#issuecomment-5203816207
https://github.com/rainlanguage/rain.dia/pull/61#issuecomment-5203816420
https://github.com/rainlanguage/rain.dia/pull/61
https://github.com/rainlanguage/rain.dia/pull/61
  rainlanguage/rain.dia#61 @ 6f1b8d666a96afb8fc411bd4b13747e505b03cb7 -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rain.math.float/pull/256#issuecomment-5203817709
https://github.com/rainlanguage/rain.math.float/pull/256#issuecomment-5203817920
https://github.com/rainlanguage/rain.math.float/pull/256
https://github.com/rainlanguage/rain.math.float/pull/256
  rainlanguage/rain.math.float#256 @ 8bc1cf70d01439d7f50e7bd893f01ec0ebb23a69 -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rain.dia/pull/57#issuecomment-5203819129
https://github.com/rainlanguage/rain.dia/pull/57#issuecomment-5203819311
https://github.com/rainlanguage/rain.dia/pull/57
https://github.com/rainlanguage/rain.dia/pull/57
  rainlanguage/rain.dia#57 @ ea63d0fb13f7b962ae183c2e150b1d5acfe869bb -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rain.math.float/pull/253#issuecomment-5203820384
https://github.com/rainlanguage/rain.math.float/pull/253#issuecomment-5203820602
https://github.com/rainlanguage/rain.math.float/pull/253
https://github.com/rainlanguage/rain.math.float/pull/253
  rainlanguage/rain.math.float#253 @ 865a49e42a4703562a1af899cc90794f6790d55c -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rain.erc4626.words/pull/252#issuecomment-5203821902
https://github.com/rainlanguage/rain.erc4626.words/pull/252#issuecomment-5203822155
https://github.com/rainlanguage/rain.erc4626.words/pull/252
https://github.com/rainlanguage/rain.erc4626.words/pull/252
  rainlanguage/rain.erc4626.words#252 @ 62c782c6c95da52bc30c4ce09fa4e46e2a91fc3a -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rain.math.float/pull/245#issuecomment-5203823251
https://github.com/rainlanguage/rain.math.float/pull/245#issuecomment-5203823462
https://github.com/rainlanguage/rain.math.float/pull/245
https://github.com/rainlanguage/rain.math.float/pull/245
  rainlanguage/rain.math.float#245 @ 0dfd28c7b18c14d9ccc170105f6af5f347bd774a -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/raindex/pull/2779#issuecomment-5203824606
https://github.com/rainlanguage/raindex/pull/2779#issuecomment-5203824853
https://github.com/rainlanguage/raindex/pull/2779
https://github.com/rainlanguage/raindex/pull/2779
  rainlanguage/raindex#2779 @ 90b1e5ecaf2a47cc41ee75d4ae7cd737382a18da -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rain.math.float/pull/244#issuecomment-5203826052
https://github.com/rainlanguage/rain.math.float/pull/244#issuecomment-5203826243
https://github.com/rainlanguage/rain.math.float/pull/244
https://github.com/rainlanguage/rain.math.float/pull/244
  rainlanguage/rain.math.float#244 @ 9b0cc58c287f416ef04dbb5597f26256b3050112 -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rain.flare/pull/160#issuecomment-5203827410
https://github.com/rainlanguage/rain.flare/pull/160#issuecomment-5203827586
https://github.com/rainlanguage/rain.flare/pull/160
https://github.com/rainlanguage/rain.flare/pull/160
  rainlanguage/rain.flare#160 @ 18712ecf512ced42397d33f46c1a9f684b8b3263 -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rainlang/pull/537#issuecomment-5203828702
https://github.com/rainlanguage/rainlang/pull/537#issuecomment-5203828911
https://github.com/rainlanguage/rainlang/pull/537
https://github.com/rainlanguage/rainlang/pull/537
  rainlanguage/rainlang#537 @ 23d605015892d5bbc29de677ba6fb2634199a29a -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rainlang/pull/536#issuecomment-5203830119
https://github.com/rainlanguage/rainlang/pull/536#issuecomment-5203830348
https://github.com/rainlanguage/rainlang/pull/536
https://github.com/rainlanguage/rainlang/pull/536
  rainlanguage/rainlang#536 @ 655a02b46c65ba0d61b03119dc7ac57236437b5c -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rainlang/pull/534#issuecomment-5203831541
https://github.com/rainlanguage/rainlang/pull/534#issuecomment-5203831759
https://github.com/rainlanguage/rainlang/pull/534
https://github.com/rainlanguage/rainlang/pull/534
  rainlanguage/rainlang#534 @ 8af4a51678f28fe1738c2b9f2f716220261ad0bd -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
https://github.com/rainlanguage/rain.math.float/pull/237#issuecomment-5203832905
https://github.com/rainlanguage/rain.math.float/pull/237#issuecomment-5203833095
https://github.com/rainlanguage/rain.math.float/pull/237
https://github.com/rainlanguage/rain.math.float/pull/237
  rainlanguage/rain.math.float#237 @ 8129870cecba51fc5b8f6954ebe05943cbbac2da -> add ai:reject, remove ai:blocked-deploy [ruling: post; work order: post]
migrated: 13 PR(s), 0 skipped (moot or live flag)

Post-run verification

$ gh search prs --label "ai:blocked-deploy" --state open --owner rainlanguage --owner cyclofinance --owner S01-Issuer --json number,repository --jq 'length'
0

$ gh pr view 61 -R rainlanguage/rain.dia --json labels,headRefOid ...
{"head":"6f1b8d666a96afb8fc411bd4b13747e505b03cb7","labels":["ai:reject"]}
  👤 human / Ruled 6f1b8d666a96afb8fc411bd4b13747e505b03cb7: reject — executing the 2026-08-06 ruling in https://github.com/r…
  Rework note @6f1b8d666a96afb8fc411bd4b13747e505b03cb7: rework the PR to fit the split release lifecycle — deploys never …

$ gh pr view 2779 -R rainlanguage/raindex ...
{"head":"90b1e5ecaf2a47cc41ee75d4ae7cd737382a18da","labels":["ai:reject"]}
  👤 human / Ruled 90b1e5ecaf2a47cc41ee75d4ae7cd737382a18da: reject — executing the 2026-08-06 ruling in https://gi…
  Rework note @90b1e5ecaf2a47cc41ee75d4ae7cd737382a18da: rework the PR to fit the split release lifecycle — depl…

$ gh pr view 237 -R rainlanguage/rain.math.float ...
{"head":"8129870cecba51fc5b8f6954ebe05943cbbac2da","labels":["ai:reject"]}
  👤 human / Ruled 8129870cecba51fc5b8f6954ebe05943cbbac2da: reject — executing the 2026-08-06 ruling in https://gi…
  Rework note @8129870cecba51fc5b8f6954ebe05943cbbac2da: rework the PR to fit the split release lifecycle — depl…

$ pr-review-report migrate-blocked-deploy --dry-run   # idempotency, live, post-migration
no open PR carries the retired ai:blocked-deploy — nothing to migrate

🤖 Generated with Claude Code

… split-lifecycle rework order

Executes the 2026-08-06 ruling in
#221 (verbatim: "migrate
all the blocked on deploy back to rejected so it can be reworked to fit in the
new deployment paradigm").

The new one-shot mirrors migrate-reject (#133): it enumerates every open PR
still carrying the RETIRED ai:blocked-deploy label (#162) live at run time,
and per PR posts the sha-pinned 👤 human ruling comment recording that the
write executes the ruling, posts the trusted Rework note carrying the uniform
split-release-lifecycle work order (the tool owns both markers — a malformed
record is unconstructible), adds ai:reject, strips other stale ai:* labels,
and removes the retired label LAST, so a mid-sequence failure leaves the PR
more parked than it started, never less. Guards per the existing plan
machinery: closed/merged is moot (nothing written), a live close-candidate
flag is reported and skipped (the strand rule), no head sha is refused for
that PR. Defaults to a report; --apply gates the write; --dry-run is the
explicit spelling of the default. Idempotent: both comments dedup, a migrated
PR re-reads as out of the population.

README: the producer-blocked residue's exit and the diagram note now record
the migration, which joins migrate-reject in the migrations-not-transitions
register. In-code prose describing the superseded eyes-on-pass exit is
updated to name the migration.

Closes #221

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

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

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

Next review available in: 25 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: 9b4a2a13-f869-4539-b86e-fd270b2a87c2

📥 Commits

Reviewing files that changed from the base of the PR and between eb03070 and fdf2ee0.

📒 Files selected for processing (3)
  • README.md
  • campaign-prompt.txt
  • pr-review-report-rs/src/main.rs

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.

thedavidmeister added a commit that referenced this pull request Aug 7, 2026
…e siblings are listed

Three things, all reconciliation with what landed and what CI actually runs.

The rust workflow's static job runs `pre-commit run --all-files` after
rainix-rs-static, and its `denofmt` hook formats markdown. It skipped
locally while nm.md was untracked, so the reflow only surfaced in CI as a
red static job. The hook's own output is now committed, and a second run
is clean.

/nd (PR 226) bumped human-fsm to 0.12.0 for its own command, which is the
version this branch had claimed. Two open PRs cannot ship the same
version — `/plugin` detects updates by comparing version STRINGS, so the
second to land would serve stale content under a version installers have
already seen. This goes to 0.13.0, which is past /nd's whichever order the
two land in.

And the three places that ENUMERATE the human's surface — CLAUDE.md's
profile table, README's human-profile paragraph, the plugin README's
command table and reads section — now name next_leak and /nm, as /nd named
next_design and /nd. An enumeration that omits a shipped tool is wrong the
moment its PR lands, and these lists are what a reader consults instead of
the tool table.

nm.md's "wrong state record" finding also picks up the retired-label case:
a label the FSM has deleted lands a PR in this queue exactly as an absent
one does. Written as the property rather than naming a label, because the
deletion in flight (#225's ai:blocked-deploy) is not the only one that will
ever happen and this command should not need editing for the next.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
thedavidmeister and others added 2 commits August 7, 2026 06:46
…ady executed

Ruling revision (2026-08-06, verbatim):
#221 (comment)
"a subcommand? i just want this migrated as a once off so we can delete the
state entirely".

The migration ran once, from this branch's earlier build, over the live
population of 13 PRs — its transcripts are in the PR body and are the once-off's
permanent record. What merges is the tree AFTER it: no subcommand, no state.

- The `migrate-blocked-deploy` subcommand is gone — Cmd variant, dispatch,
  plan/steps/search machinery, its tests. Machinery for an empty population is
  dead weight.
- `ai:blocked-deploy` is deleted from the FSM, compiler-first: the constant went
  first and rustc enumerated every consumer — the classify_lane arm, the
  blockedDeploy counts key, the human-queue display section, the label_meta row,
  the next_action parking arm. The label now classifies as NOTHING: unmodelled,
  so a PR wearing it takes the ordinary fallthrough (producer-commented -> leak,
  the /nm queue; otherwise un-vetted), parks nothing, and blocks nothing.
- The label DEFINITION is deleted from all 6 repos that carried it across the
  three orgs (zero open PRs were wearing it, so nothing was destroyed).
- README and the campaign prompt drop the residue/migration prose; #162's live
  rule stays: a deploy-shaped block means the REPO has not migrated, expressed
  as a typed ai:blocked-on.

Closes #221

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The deletion-scoped mutation pass found this gap: resurrecting the
`ai:blocked-deploy` row in `label_meta` SURVIVED the whole suite. That table
feeds `gh label create --force`, so a surviving row is what would let the next
thing that named the string re-create the definitions this PR deleted from all
six repos. Strengthened in place, on the existing retirement test, against an
arbitrary unknown label rather than literal bytes — with the deliberate contrast
that retired-but-occupied `ai:blocked-infra` KEEPS its row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thedavidmeister thedavidmeister changed the title migrate-blocked-deploy: the retired residue moves to ai:reject with a split-lifecycle rework order ai:blocked-deploy: migrated as a once-off, state deleted Aug 7, 2026
Review caught that the "surfaces as a leak" outcome is UNREACHABLE in
production, and the tests had been shaped to reach it.

`human_queue_mode` buckets every `ai:*`-labelled PR through `ai_state_label`
and leak-detects only the `unlabeled` remainder, so `leak_keys` — the sole
source of `producer_commented` — can never contain a PR carrying an `ai:*`
label. `classify_lane`'s own contract says the flag is "for a label-less PR".
So a PR hand-wearing the deleted `ai:blocked-deploy` string is
`(VetLifecycle, "un-vetted")`: the vetter absorbs it and the verdict that
judges it strips the dead label. Benign, but not what the tests, the comments
or the README claimed.

- `the_deleted_blocked_deploy_label_classifies_as_nothing` drops the
  unreachable `producer_commented: true` assertion and documents WHY false is
  the only constructible input.
- `lanes_doc_emits_every_state_with_the_right_members` feeds the fixture the
  way the pipeline feeds it (`qpr(8, …, false)`) and asserts the un-vetted
  outcome — including #8 by number in the un-vetted member list, so a
  regression in how unmodelled `ai:*` labels route is now visible. Restores
  `count("leak","leak") == 1`.
- README's producer-blocked lane doc states the un-vetted truth and says why
  it is not a leak.
- NITs: process narration dropped from the classify_lane test doc; the
  label_meta comment no longer overstates a missing row (the function is
  total — an absent row yields the generic fallback).

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

Copy link
Copy Markdown
Contributor Author

Reviewed fdf2ee0: approve — read the full diff independently. The once-off executed (13 PRs migrated, transcripts in the body) and the subcommand that ran it is gone: zero occurrences of migrate_blocked_deploy, MigrateBlockedDeploy or RETIRED_BLOCKED_DEPLOY_LABEL survive. The state is deleted compiler-first — classifier arm, counts emission, human-queue display section, label_meta row and next_action parking arm all absent, with the 13 surviving string mentions being doc comments explaining the absence and tests pinning it. Net 155 insertions against 191 deletions. #162's live rule survives intact (a deploy-shaped block means the repo has not migrated → typed ai:blocked-on). Label definitions swept from all 6 defining repos of 134 scanned, 0 remaining except one archived repo that refuses writes. 1002 tests green, 20/20 checks, 6/6 resurrection mutants killed — including the label_meta row, whose survival would have let gh label create --force re-create the definitions this PR just deleted.
Rulings-conformance: checked against CLAUDE.md and every ruling stated for this work. (1) 'migrate all the blocked on deploy back to rejected so it can be reworked to fit in the new deployment paradigm' (2026-08-06) — executed, 13 PRs, verified zero residue org-wide. (2) 'a subcommand? i just want this migrated as a once off so we can delete the state entirely' — no subcommand survives; the state is deleted entirely; the transcripts remain as the once-off's record. (3) removal-is-semantic-not-grep — deletion done compiler-first, read-verified, not grep-quiet. (4) comments describe CURRENT behavior only — the 'eyes-on human pass' prose is gone from README, campaign-prompt and every code comment that carried it. (5) the unreachable 'surfaces as a leak' claim was corrected to the un-vetted truth in code, tests and README after review, with the fixture no longer fed an input the pipeline cannot construct. The artifact obeys each.

@thedavidmeister
thedavidmeister merged commit b084ee2 into main Aug 7, 2026
21 checks passed
thedavidmeister added a commit that referenced this pull request Aug 7, 2026
…ranch

Two independent DELETIONS of an FSM state landed on the same regions: #221/#225
deleted `ai:blocked-deploy`, this branch deletes `human:design`. Every conflict
was that symmetry, and every one takes BOTH deletions rather than a side.

- classify_lane's lanes fixture now carries residue of both deleted labels, so
  the un-vetted bucket gains a member from each: count 3 -> 4, members
  [1, 2, 8, 12]. Neither deleted state emits a lane cell.
- the domination case keeps this branch's subject (the retired `human:reject`
  is the human-decisions lane's one remaining state, not the deleted
  `human:design`) over main's, and main's spelling of the deploy label: a bare
  literal, because #225 deleted the constant and re-declaring one to name a
  state that does not exist would be the deletion undone.
- README's lane list takes main's producer-blocked bullet whole and this
  branch's human-decisions bullet whole.

next_action auto-merged correctly and is the interaction worth stating: main
removed the deleted label from the modeled-state park arm, this branch added
the reject arm directly beneath it, and the result keeps both — a note-less
`ai:reject` still classifies parked-skip and nothing parks on the deleted
deploy label. The derived action vocabulary needed no edit at all: #225 added
and retired no NextAction variant, and the exhaustive rank()/names_work()
matches would have refused to compile if it had.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
thedavidmeister added a commit that referenced this pull request Aug 7, 2026
…) into /nm

Both deletions land under a PR whose whole subject is "which PRs are in no
modeled state", so the interactions are the merge, not a side effect of it.

CONFLICT SHAPE: two files, both the plugin version JSONs, both trivial —
main carries #224's 0.12.0 and this branch 0.13.0, and mine is the superset
(it names /nm) and is already ahead. main.rs auto-merged CLEAN, which is
exactly the case that has bitten twice today, so the real work was hunting
what the markers could not show.

WHAT THE SUITE CAUGHT THAT THE MARKERS DID NOT:

- The drift witness in `a_row_carries_the_leaks_own_evidence` asserted a
  `human:design` PR classifies into the human-decisions lane. #224 deleted
  that state, so it now classifies as a LEAK and the assertion failed on the
  merge commit. Repointed at `human:reject` — the lane's one surviving state,
  and still the live instance of the hazard the field exists for (a `human:*`
  label carries no `ai:*` prefix, which is what the old population wrongly
  admitted).
- `is_leak_candidate` referenced `RETIRED_BLOCKED_DEPLOY_LABEL`, deleted by
  #225: a compile error, fixed by dropping the row.

WHAT ONLY READING #225's OWN COMMIT CAUGHT — and no test would have:

`fdf2ee0` ruled that a PR hand-wearing a DELETED `ai:*` string lands
`un-vetted`, not `leak`, because the vetter absorbs it and the verdict that
judges it strips the dead label. That ruling was justified by the caller-side
`ai_state_label` partition — the exact thing this PR replaced with a
classifier-derived population. Under the merge as it auto-resolved, such a PR
became a leak again and silently overturned a ruling that landed hours ago.
The `lanes_doc` fixture cannot catch it (it feeds `producer_commented`
directly), so this is added as a conjunct on `is_leak_candidate` with the
ruling cited, plus an assertion over the registry below. It cannot reintroduce
the defect this predicate exists to fix: that defect was `human:*` labels
parked in a real lane, and the classifier arm is what excludes those.

THE THREE PIECES OF COVERAGE THE HUMAN CALLED FOR, so none of the above is
re-verified by hand at the next merge:

1. `every_lane_is_reachable_from_some_label_set` — one witness per `Lane`,
   driven off a new `Lane::ALL`, so an arm going unreachable behind a
   precedence change is a failure and a lane added later is covered on the day
   it is added.
2. `DELETED_LABELS` + `a_deleted_label_models_nothing_anywhere` — one property
   over a registry, replacing the two bespoke per-deletion tests #219 and #221
   each shipped. For every deleted label: the ordinary unmodelled fallthrough,
   dominates nothing, occupies no lane cell (checked across `Lane::ALL`), and
   no `counts` key names it. The next deletion adds a row of DATA.
3. `lanes_doc_emits_every_state_with_the_right_members` now derives every
   total from per-row expectations instead of literals. That assertion is the
   one that read `3` on two branches and was wrong at `4` once both landed,
   with nothing pointing at it; an expectation beside its input cannot go
   stale that way.

nm.md, the README and the doc comments now state the post-deletion truth: a
RETIRED label stays bucketed and never leaks; a deleted `ai:*` label is
absorbed as un-vetted; a deleted `human:*` label DOES leak, because the
vetter's sweep is `ai:*`-scoped and nothing else claims it. The classifier
rule nm.md tells the human to check is now its three real clauses rather than
the `ai:*`-only paraphrase.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
thedavidmeister added a commit that referenced this pull request Aug 7, 2026
…) 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>
thedavidmeister pushed a commit that referenced this pull request Aug 7, 2026
… drain

`migrate-needs-work` was the #133 one-shot: move every open PR still carrying
the RETIRED PR-side `human:needs-work` onto `ai:needs-work`. It has run. Across
`rainlanguage` + `cyclofinance` + `S01-Issuer` the open-PR population on that
label is now ZERO (the two remaining subjects are closed PRs), which is the same
residue-zero bar #225 held `migrate-blocked-deploy` to. Per the standing ruling
on #221 a migration is an
execution vehicle rather than permanent machinery, so the verb comes out with
the state it drained — exactly as `migrate-blocked-deploy` (#225) and
`migrate-design` (#224) did, each leaving only a test that the subcommand no
longer parses.

There is no separate `migrate-reject`: this branch had renamed that verb to
`migrate-needs-work`, so both spellings go with this one deletion.

Done compiler-first — the `Cmd` variant, its dispatch arm, the plan/mode
machinery and its tests, then `RETIRED_HUMAN_NEEDS_WORK_LABEL` itself, following
every rustc error rather than re-literalising anything to keep the tree
compiling. That cascade is larger than the subcommand, because the retired label
was the last thing holding the PR-side sacred-label machinery up:

- `PR_SACRED_LABELS` had one entry, so it and `has_human_override` are gone. A
  PR's human-sacredness is now exactly what #133/#219 said it should be: a
  native review, or a `👤 human` ruling pinned to the current head. No label.
- `PrSignals.human_parked` and `next_action`'s parking arm — #225's list names
  this one explicitly. Parking is now a modeled `ai:*` state, not a namespace.
- `STATE_HUMAN_NEEDS_WORK`, its `classify_lane` arm, its daily-review section,
  and `Lane::HumanDecisions` — the lane held that one state, so it drained to
  nothing and came out with it.
- `DesignHit::HumanRuled` and `/nd`'s `humanRuled` count, whose only producer
  was `has_human_override`. `aiDesign`'s stated partition loses that term.
- The worklist row's `humanOverride` key, for the same reason. Nothing outside
  the binary read it.

`human:needs-work` is NOT added to `DELETED_STATE_LABELS`, deliberately. That
registry claims no transition can write the string again, and on an ISSUE that
is false: `human-rule-issue needs-work` still writes it and 21 open issues carry
it today. Only the PR-side state was removed, so the lane-arithmetic test names
the string locally and says why.

What the compiler could NOT see, and the suite caught: fourteen tests built
their human-sacred witness from the string literal `"human:needs-work"` rather
than the constant, so they compiled clean and then failed — the verdict/scope/
lens/convention gates, the MCP refusal, `producer_state_plan`, the state-load
fixture's 36-PR cohort, and the golden descriptor and lane rows. Each now uses a
form that is still a human decision (a native review), or asserts the new truth.
The last grep sweep then found what neither reached: prose in README.md,
CLAUDE.md, `keep-open.md` and `nm.md`, plus the subcommand's row in CLAUDE.md's
table — seven documentation sites with no compiler or test coverage at all.

Counts re-derived from the merged table rather than carried across:
`STATE_DESCRIPTORS` 12 -> 11, `REVIEW_LANE_SECTIONS` 8 -> 7, `Lane::ALL` 6 -> 5.

Gates: `cargo test` 1047+3+9+47+8+7+4 passed 0 failed; CI-exact
`rainix-rs-static` at rainix 53e96a7 with the changed file touched first;
`pre-commit run --all-files`; `nix build .#pr-review-report`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

RULED: migrate the ai:blocked-deploy residue to ai:reject — rework each PR for the split release lifecycle

1 participant