@rtorcato/repo-tooling 3.17.0 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,10 +39,15 @@ export const LOOP_LABELS = [
39
39
  color: 'fbca04',
40
40
  description: 'Passed, but a reviewer left something to read before merging',
41
41
  },
42
+ {
43
+ name: 'ai-suggested',
44
+ color: 'c2e0c6',
45
+ description: 'Follow-up surfaced by an agent review — triage queue, never auto-picked',
46
+ },
42
47
  ];
43
48
  /**
44
49
  * How many of the set have to exist before this repo counts as running the
45
- * loop. A repo with none has opted out, not drifted — creating eleven labels it
50
+ * loop. A repo with none has opted out, not drifted — creating twelve labels it
46
51
  * will never use is the nag this threshold exists to prevent. One alone is the
47
52
  * observed half-state (`cf-common` has only `ai-ready`, applied by hand), which
48
53
  * is likewise not evidence the pipeline runs there.
@@ -141,7 +146,7 @@ export async function checkLoopLabels(dir, exec) {
141
146
  * Repairs colour and description with `gh label edit`, and creates the labels
142
147
  * the set is missing. Only on a repo already running the loop (the same
143
148
  * `IN_USE_THRESHOLD` gate the check uses) — otherwise a plain `fix --yes` would
144
- * push eleven labels into every repo it touches.
149
+ * push twelve labels into every repo it touches.
145
150
  *
146
151
  * Idempotent: an aligned repo is a no-op, and a label whose only difference is
147
152
  * the hex case is not touched at all.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/repo-tooling",
3
- "version": "3.17.0",
3
+ "version": "3.18.0",
4
4
  "description": "One CLI to scaffold, audit and fix your repo's whole toolchain — linting, tests, commits, releases & CI.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -60,6 +60,7 @@ drift with a second copy to maintain.
60
60
  |---|---|
61
61
  | Clean and ready | **None.** `ai-ok-code, ai-ok-sec` + assigned + no `ai-review` already says it. |
62
62
  | `ai-notes` | ≤10 lines; link the reviewer's `### Before merging`. |
63
+ | Follow-up found | One line — `Follow-up: #<new>`. The issue carries the context. |
63
64
  | `ai-changes`, CI red, `ai-blocked` | ≤10 lines, action first, then the specific cause. |
64
65
  | Reviewer verdict | `### Before merging` plus ≤600 characters above it. |
65
66
  | Declining an issue | The one exception — a hard handoff needs its reasoning; see Pass 4. |
@@ -78,6 +79,7 @@ drift with a second copy to maintain.
78
79
  | `ai-ok-sec` | PR | `security-expert` passed. |
79
80
  | `ai-changes` | PR | A reviewer requested changes. Reviewers never apply it to a Dependabot PR. |
80
81
  | `ai-notes` | PR | Passed, but a reviewer left something to read before merging. |
82
+ | `ai-suggested` | issue | Follow-up a reviewer filed. A triage queue, never auto-picked. |
81
83
  | `holding` | issue | A gate — closes on human judgement, never picked up. |
82
84
 
83
85
  **`ai-notes` is advisory and never blocks.** It rides *alongside* a pass label,
@@ -87,12 +89,19 @@ so `ai-notes` is the hold itself: it suppresses auto-merge and routes the PR to
87
89
  the human. It exists because a pass label currently means both "clean" and
88
90
  "I found something real but would not hold the PR over it", and those two are
89
91
  indistinguishable in the *Assigned to you* view where merges actually happen.
90
- The bar is a finding that **changes what a human would do**: a semver
91
- implication, a deliberate omission, a follow-up that must be filed. Not
92
+ The bar is a finding that **changes what a human would do at merge time**: a
93
+ semver implication, a deliberate omission, a question only they can answer. Not
92
94
  observations, not praise, not restating the diff. `ai-notes` on every PR is the
93
95
  failure mode — it trains the reader to ignore it, which is worse than not having
94
96
  it.
95
97
 
98
+ **Follow-up work is an issue, not a note.** A finding that clears that bar *and*
99
+ is work someone would plausibly do gets filed as its own issue labelled
100
+ `ai-suggested`, by the reviewer that found it; the PR comment keeps one line and
101
+ a link. It does **not** earn `ai-notes` — later work does not decide this merge.
102
+ An observation is not a follow-up. Prose in a merged PR's comments is
103
+ archaeology, which is how every follow-up left there so far has died on merge.
104
+
96
105
  First run in a repo, create any that are missing (`gh label create` is a no-op
97
106
  error if it exists — ignore that):
98
107
 
@@ -108,6 +117,7 @@ gh label create ai-ok-code -c '#0e8a16' -d 'code-reviewer passed'
108
117
  gh label create ai-ok-sec -c '#0e8a16' -d 'security-expert passed'
109
118
  gh label create ai-changes -c '#d93f0b' -d 'Reviewer requested changes'
110
119
  gh label create ai-notes -c '#fbca04' -d 'Passed, but a reviewer left something to read before merging'
120
+ gh label create ai-suggested -c '#c2e0c6' -d 'Follow-up surfaced by an agent review — triage queue, never auto-picked'
111
121
  ```
112
122
 
113
123
  Bootstrap only. `gh label create` **cannot repair a label that already exists** —
@@ -539,10 +549,28 @@ Reviewer prompt template:
539
549
  > narrate only where the PR is **wrong** or **silent**. Never list what you
540
550
  > checked and found clean, and never confirm a claim the PR body already makes —
541
551
  > agreement is what the pass label is for, so a review that agrees is nearly
542
- > empty. The bar is a finding that **changes what a human would do**: a semver
543
- > implication, a deliberate omission, a follow-up that must be filed. Writing
544
- > `Nothing.` is a real verdict and the common one — say it plainly rather than
545
- > padding to look thorough.
552
+ > empty. The bar is a finding that **changes what a human would do at merge
553
+ > time**: a semver implication, a deliberate omission. Writing `Nothing.` is a
554
+ > real verdict and the common one — say it plainly rather than padding to look
555
+ > thorough.
556
+ >
557
+ > **Follow-up work is an issue, and you file it — it does not go in that
558
+ > section.** When a finding clears that bar but is work someone would plausibly
559
+ > do *later* rather than something that decides this merge:
560
+ >
561
+ > ```bash
562
+ > gh issue create --label ai-suggested --title "<what to do>" --body "🤖 *Automated — \`<your agent type>\` via ai-issue-loop.*
563
+ >
564
+ > Surfaced reviewing #<N>. <What, and why it matters. A few lines.>"
565
+ > ```
566
+ >
567
+ > Then put `Follow-up: #<new>` on one line in the body above `### Before
568
+ > merging` and keep it out of that section, so it does not pull `ai-notes` in —
569
+ > later work is not a merge gate. GitHub cross-links the two, so the trail
570
+ > survives the merge in both directions; the comment prose does not. Filing is
571
+ > the alternative to blocking, not a precondition for it. An observation is not
572
+ > a follow-up — do not file one, and a trade-off that changes nothing a human
573
+ > does is one line of body and nothing else.
546
574
  >
547
575
  > Then apply exactly one verdict label, **clearing your claim label in the same
548
576
  > command**:
@@ -655,6 +683,12 @@ package/from/to table survives because it sits at the top; classify from that.
655
683
  > unattended. A major, a package that ships to consumers, or a truncated body you
656
684
  > could not fully read **is** worth a note; restating the version table on a
657
685
  > routine dev-only patch bump is not.
686
+ >
687
+ > **Follow-up work is an issue here too** — same `gh issue create --label
688
+ > ai-suggested` as the generic prompt, same `Follow-up: #<new>` one-liner in the
689
+ > body, never in `### Before merging`. That separation matters more on this arm
690
+ > than the other: a note here costs a human the merge, so routing "someone should
691
+ > pin this transitive dep one day" to an issue is what keeps auto-merge usable.
658
692
 
659
693
  Be honest about what this buys: an agent reading a version table catches majors,
660
694
  production-dependency creep, and a renamed or newly-added package. It does **not**
@@ -727,6 +761,7 @@ gh api "repos/$OWNER_REPO/issues?labels=ai-ready&state=open" \
727
761
  | select([.labels[].name] | index("ai-wip") == null)
728
762
  | select([.labels[].name] | index("ai-blocked") == null)
729
763
  | select([.labels[].name] | index("holding") == null)
764
+ | select([.labels[].name] | index("ai-suggested") == null)
730
765
  | select(.author_association=="OWNER" or .author_association=="MEMBER" or .author_association=="COLLABORATOR")
731
766
  | {number, title}'
732
767
  ```
@@ -741,6 +776,10 @@ the first place, but then mislabelling it costs nothing. Unlike `ai-blocked` (an
741
776
  agent tried and got stuck), `holding` says *no agent should ever start*, and it
742
777
  shows up in the issue list so a human triaging does not re-litigate it either.
743
778
 
779
+ `ai-suggested` is excluded for a harder reason: it is an agent's own suggestion,
780
+ so picking one up would let the loop feed itself work — promoting one is a human
781
+ act, which is what makes that label a triage queue rather than a backlog.
782
+
744
783
  **Declining an issue is a visible act — comment, never just skip.** Whenever an
745
784
  agent decides an issue should *not* go to the pipeline — triaging which issues to
746
785
  label `ai-ready`, or dropping one that is already labelled — say so on the issue