@clipboard-health/ai-rules 2.29.9 β†’ 2.29.10

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipboard-health/ai-rules",
3
- "version": "2.29.9",
3
+ "version": "2.29.10",
4
4
  "description": "Pre-built AI agent rules for consistent coding standards.",
5
5
  "keywords": [
6
6
  "ai",
@@ -27,9 +27,9 @@ This skill always runs exactly one pass. It never waits or repeats internally. F
27
27
 
28
28
  The skill uses two sentinels. Each is a visible footer line wrapped in `<sub>` (a πŸ€– mark plus the token in `<code>`).
29
29
 
30
- **Addressed sentinel**: `<sub>πŸ€– <code>babysit-pr:addressed v1 core@3.9.0</code></sub>`. Appended on its own line at the end of every reply the skill posts (both thread replies and the review-body summary); this is how re-runs know which threads and review-body comments are already handled. Dedupe matches the version-agnostic substring `babysit-pr:addressed v1` followed by a space (also matches legacy `<!-- babysit-pr:addressed v1 ... -->` sentinels). Grep `babysit-pr:addressed v1` for any version; add `core@3.9.0` for a specific one.
30
+ **Addressed sentinel**: `<sub>πŸ€– <code>babysit-pr:addressed v1 core@3.10.1</code></sub>`. Appended on its own line at the end of every reply the skill posts (both thread replies and the review-body summary); this is how re-runs know which threads and review-body comments are already handled. Dedupe matches the version-agnostic substring `babysit-pr:addressed v1` followed by a space (also matches legacy `<!-- babysit-pr:addressed v1 ... -->` sentinels). Grep `babysit-pr:addressed v1` for any version; add `core@3.10.1` for a specific one.
31
31
 
32
- **Follow-up sentinel**: `<sub>πŸ€– <code>babysit-pr:followup v1 core@3.9.0</code></sub>`. Attached to replies that defer an out-of-scope comment as a tracked follow-up (see the Scope subsection and the Defer verdict in step 6). Grep `babysit-pr:followup` across PR conversation JSON to enumerate deferred items. This sentinel is additive β€” the post-reply scripts still append the `addressed` sentinel at the end, so a deferred thread is correctly machine-classified as addressed (the skill _has_ handled it β€” by deferring). Human reviewers and future sweeps distinguish deferred from resolved by looking for the follow-up sentinel.
32
+ **Follow-up sentinel**: `<sub>πŸ€– <code>babysit-pr:followup v1 core@3.10.1</code></sub>`. Attached to replies that defer an out-of-scope comment as a tracked follow-up (see the Scope subsection and the Defer verdict in step 6). Grep `babysit-pr:followup` across PR conversation JSON to enumerate deferred items. This sentinel is additive β€” the post-reply scripts still append the `addressed` sentinel at the end, so a deferred thread is correctly machine-classified as addressed (the skill _has_ handled it β€” by deferring). Human reviewers and future sweeps distinguish deferred from resolved by looking for the follow-up sentinel.
33
33
 
34
34
  **Sentinel recency rules.** The script emits a per-thread `activityState` with three values:
35
35
 
@@ -280,7 +280,7 @@ Body templates (the script appends the `addressed` sentinel if missing):
280
280
  - **Agree**: `Addressed in <commit-url>. <one-line what-changed>.`
281
281
  - **Disagree**: `Leaving current behavior. <reasoning>.`
282
282
  - **Already fixed**: `Already handled by <commit-url-or-file:line>. <brief pointer>.`
283
- - **Defer**: `Out of scope for this PR; this looks like follow-up work rather than something introduced or required by this change. <one-line rationale or pointer if useful>.\n\n<sub>πŸ€– <code>babysit-pr:followup v1 core@3.9.0</code></sub>`
283
+ - **Defer**: `Out of scope for this PR; this looks like follow-up work rather than something introduced or required by this change. <one-line rationale or pointer if useful>.\n\n<sub>πŸ€– <code>babysit-pr:followup v1 core@3.10.1</code></sub>`
284
284
 
285
285
  For Defer replies, include the follow-up sentinel on its own line as shown. The script will append the `addressed` sentinel after it on its own line, so the final body ends with the follow-up sentinel followed by a blank line followed by the `addressed` sentinel β€” `grep babysit-pr:followup` finds the deferral and `grep babysit-pr:addressed` still marks the thread handled for dedupe.
286
286
 
@@ -296,7 +296,7 @@ The PR-level summary should:
296
296
 
297
297
  - Group by source. Use `## Review-body findings` for step-7 work and `## Conversation-tab comments` for step-6b work. Omit a section if its list is empty.
298
298
  - Inside each section, group verdicts under **Agree / Disagree / Already fixed / Deferred (out of scope)** subheadings. Omit a subheading if its list is empty.
299
- - Under **Deferred (out of scope)**, list each deferred item as a bullet, followed on its own line by `<sub>πŸ€– <code>babysit-pr:followup v1 core@3.9.0</code></sub>` so grep catches them individually.
299
+ - Under **Deferred (out of scope)**, list each deferred item as a bullet, followed on its own line by `<sub>πŸ€– <code>babysit-pr:followup v1 core@3.10.1</code></sub>` so grep catches them individually.
300
300
  - Include the commit URL for fixes.
301
301
  - End with a fenced fingerprint block listing every current fingerprint β€” addressed and deferred β€” one per line. Include both `reviewBodyComments[].fingerprint` (whole-body, one per automated review) and `activeIssueComments[].fingerprint` (per Conversation-tab comment). Future runs dedupe by matching these against `priorBabysitSentinels`.
302
302
 
@@ -9,7 +9,7 @@
9
9
  # substituted at build time by embedPluginVersion.mts.
10
10
 
11
11
  SENTINEL_PREFIX='babysit-pr:addressed v1 '
12
- SENTINEL='<sub>πŸ€– <code>babysit-pr:addressed v1 core@3.9.0</code></sub>'
12
+ SENTINEL='<sub>πŸ€– <code>babysit-pr:addressed v1 core@3.10.1</code></sub>'
13
13
 
14
14
  # Bot author allowlist (JSON array literal). Used by unresolvedPrComments.sh
15
15
  # as a fallback when GraphQL's `author.__typename == "Bot"` misses a GitHub
@@ -47,7 +47,7 @@ Script paths in this procedure are written as `scripts/...`, relative to this SK
47
47
  6. Check for an existing PR with `gh pr view`.
48
48
 
49
49
  PR title format: conventional-commit type + description, with no scope, plus the Linear ticket in parentheses at the end when one applies (e.g., `feat: add resume command (STAFF-123)`). This differs from the commit subject, which keeps its scope. Derive the ticket from the branch name, commit body, or session context; omit the parenthetical when no ticket applies.
50
- - No PR: create with `gh pr create` using the PR title format above. Description = the PR body shape above, followed by the session footer line if known and the agent footer `<sub>πŸ€– <code>commit-push-pr:created v1 core@3.9.0</code></sub>` on its own line.
51
- - PR exists: if the title doesn't match the format above, correct it with `gh pr edit --title`. Refresh the body via `gh pr edit --body` so (a) the new commit's changes are reflected in the prose while existing `## Summary`, `## Validation`, and `## Notes` sections are preserved unless clearly stale, (b) any known session footer line is appended if missing, never removing or rewriting existing `Agent session: ...` or `Agent session ID: ...` lines, and (c) any existing footer carrying the substring `commit-push-pr:created v1` is preserved verbatim, appending `<sub>πŸ€– <code>commit-push-pr:created v1 core@3.9.0</code></sub>` only if absent. Then report the URL.
50
+ - No PR: create with `gh pr create` using the PR title format above. Description = the PR body shape above, followed by the session footer line if known and the agent footer `<sub>πŸ€– <code>commit-push-pr:created v1 core@3.10.1</code></sub>` on its own line.
51
+ - PR exists: if the title doesn't match the format above, correct it with `gh pr edit --title`. Refresh the body via `gh pr edit --body` so (a) the new commit's changes are reflected in the prose while existing `## Summary`, `## Validation`, and `## Notes` sections are preserved unless clearly stale, (b) any known session footer line is appended if missing, never removing or rewriting existing `Agent session: ...` or `Agent session ID: ...` lines, and (c) any existing footer carrying the substring `commit-push-pr:created v1` is preserved verbatim, appending `<sub>πŸ€– <code>commit-push-pr:created v1 core@3.10.1</code></sub>` only if absent. Then report the URL.
52
52
 
53
53
  7. End with one short text response: branch name and the full PR URL (e.g., `https://github.com/clipboardhealth/core-utils/pull/123`). Never use shorthand like `repo#123` β€” always output the complete URL.
@@ -131,7 +131,7 @@ Every finding **must** include a `failure_mode`: one sentence on the concrete us
131
131
 
132
132
  ### Do-not-raise list (binding)
133
133
 
134
- - Speculative defensiveness at trusted internal boundaries.
134
+ - Speculative defensiveness at trusted internal boundaries (only where the boundary's guarantee is actually _enforced_ β€” a declared or cast type is not enforcement; see AntiSlop).
135
135
  - Restating the obvious ("consider a comment explaining what this does").
136
136
  - Hypothetical future-caller scenarios with no current caller.
137
137
  - Style/formatting a linter or formatter covers.
@@ -150,6 +150,8 @@ For every candidate finding, run the litmus test before keeping it: _"What is th
150
150
 
151
151
  For each change name a realistic input or condition that would expose a bug. If you cannot, do not raise it.
152
152
 
153
+ - **Declared β‰  enforced β€” check what actually guarantees a precondition.** When new code performs an operation that faults on a missing or malformed input (destructuring, property/array access, non-null assertion, iteration, parsing, arithmetic), do not accept a declared type, function signature, cast, or `as` as proof the input is safe β€” those _label_ a value, they don't _check_ it. Ask what enforces the precondition on this path: a runtime validator, a preceding explicit check, or a constructor/factory invariant. If nothing does, trace the value to its origin β€” it can fault on real data even though it compiles. Look at the operation that would actually throw, not only the named field beside it.
154
+ - **Asymmetric handling across sibling call sites is a likely bug, not a style nit.** When the diff guards, validates, converts, or error-wraps a value in one place but consumes the same value or shape bare elsewhere, exactly one side is usually right. Compare the call sites against each other instead of reviewing each in isolation, and resolve the inconsistency: guard missing where it's absent β†’ bug; guard unnecessary everywhere β†’ slop to remove.
153
155
  - Edge cases, error paths, observability of real failure modes.
154
156
  - Tests cover real risk, not lines.
155
157
  - Concurrency, performance at real scale, data integrity.
@@ -212,7 +214,7 @@ Tag every convention finding with `[CONVENTION]` in the title. Cap severity at M
212
214
 
213
215
  This PR may have been written or assisted by an LLM. For each addition, ask: _"Is this line earning its keep, or is it pattern-matching what code is supposed to look like?"_ Push back on what other lenses are too polite to flag. Apply to additions **inside the diff itself**.
214
216
 
215
- - **Defensive code at trusted internal boundaries.** Null guards on private helpers whose callers' types guarantee non-null; `try`/`catch` wrapping a single non-throwing call, or that re-throws unchanged, or that "logs and swallows" without naming what to do next; optional-chaining through types that don't include optionality.
217
+ - **Defensive code at trusted internal boundaries.** Null guards on private helpers whose callers' types guarantee non-null; `try`/`catch` wrapping a single non-throwing call, or that re-throws unchanged, or that "logs and swallows" without naming what to do next; optional-chaining through types that don't include optionality. **But "trusted" means the guarantee is _enforced_** β€” by a validator on this path, a constructor/factory invariant, or a preceding check you can point to. A type, signature, cast, or `as`/non-null-assertion only _asserts_ the guarantee; a guard backing a merely-asserted guarantee is load-bearing, not slop. Confirm what enforces the type at the call site before flagging the guard.
216
218
  - **Defensiveness against unrealistic product scenarios.** Litmus: _"In the real product flow this code participates in, what user action / system event / upstream call could land us in this branch?"_ If the answer is "none" or "I had to invent one to justify the guard", it's slop. Concrete shapes:
217
219
  - Null/undefined guard on an ID immediately after that ID was used to load (and find) the entity.
218
220
  - A `null`/`undefined`/`""`/`0` branch on a field whose TypeScript or Zod/class-validator already rejects those.
@@ -282,7 +284,7 @@ Does this follow our FE conventions, and will it behave correctly under realisti
282
284
  After walking the checklist, apply these filters to your candidate findings:
283
285
 
284
286
  1. **Drop findings with empty or hypothetical `failure_mode`.** "A future caller might…", "in case someone…" β†’ drop.
285
- 2. **Self-audit for slop.** For every finding you wrote, ask: does it match a slop pattern (asks-for-defensive-guard on already-narrowed value; hypothetical future caller; restating-obvious comment request; abstract refactor with no concrete cost-of-keeping; observability without named failure mode; test for trivially-verifiable code; defends against a state the product cannot produce)? If yes and you can't write a concrete, product-specific cost in one sentence β€” drop it. Being your own AntiSlop reviewer is the main lever for keeping this skill honest.
287
+ 2. **Self-audit for slop.** For every finding you wrote, ask: does it match a slop pattern (asks-for-defensive-guard on an already-narrowed value β€” but only if an _enforced_ check narrows it, not merely a declared type or cast (see Engineering's declared β‰  enforced); hypothetical future caller; restating-obvious comment request; abstract refactor with no concrete cost-of-keeping; observability without named failure mode; test for trivially-verifiable code; defends against a state the product cannot produce)? If yes and you can't write a concrete, product-specific cost in one sentence β€” drop it. Being your own AntiSlop reviewer is the main lever for keeping this skill honest.
286
288
  3. **Cross-repo audit.** For every finding, ask: does the failure_mode reference a downstream actor (FE, mobile, consumer service, rolling deploy, external library user) or a contract/schema/public-artifact boundary? If yes, did you actually read the relevant external file(s) to confirm the claim, or are you reasoning from priors about "how FEs usually work"? If you didn't read it, the finding is cross-repo β€” route to the Cross-repo evidence policy (verify, ask for access, or downgrade to a clearly-labeled "speculative" MINOR). Do not ship a "consumer will break" finding sourced from imagination.
287
289
  4. **Drop do-not-raise items** that slipped through.
288
290
  5. **Apply the NIT gate.** NITs that don't meet (a)/(b)/(c) β†’ drop. Kept internally but hidden by default in synthesis.