@clipboard-health/ai-rules 2.14.18 → 2.14.20
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 +1 -1
- package/scripts/sync.js +3 -3
- package/skills/write-bug-ticket/SKILL.md +5 -2
- package/skills/write-bug-ticket/reference.md +4 -0
- package/skills/write-feature-ticket/SKILL.md +4 -2
- package/skills/write-feature-ticket/examples.md +6 -0
- package/skills/write-feature-ticket/red-flags.md +1 -0
- package/skills/write-tech-debt-ticket/SKILL.md +23 -16
- package/skills/write-tech-debt-ticket/reference.md +8 -0
package/package.json
CHANGED
package/scripts/sync.js
CHANGED
|
@@ -105,7 +105,7 @@ function printUsageAndExit() {
|
|
|
105
105
|
}
|
|
106
106
|
function resolveRuleIds(parsedArguments) {
|
|
107
107
|
const { profile, extraIncludes, excludes } = parsedArguments;
|
|
108
|
-
const profileRules = constants_1.PROFILES[profile].include.flatMap((category) =>
|
|
108
|
+
const profileRules = constants_1.PROFILES[profile].include.flatMap((category) => constants_1.CATEGORIES[category]);
|
|
109
109
|
const ruleSet = new Set([...profileRules, ...extraIncludes]);
|
|
110
110
|
for (const ruleId of excludes) {
|
|
111
111
|
ruleSet.delete(ruleId);
|
|
@@ -205,7 +205,7 @@ async function mergeSessionStartHook() {
|
|
|
205
205
|
// commands that may share the same entry. Drop entries left with no hooks.
|
|
206
206
|
const cleaned = sessionStart.flatMap((entry) => {
|
|
207
207
|
const entryHooks = entry["hooks"];
|
|
208
|
-
if (
|
|
208
|
+
if (entryHooks?.some((h) => isKnownCommand(h)) !== true) {
|
|
209
209
|
return [entry];
|
|
210
210
|
}
|
|
211
211
|
const remaining = entryHooks.filter((h) => !isKnownCommand(h));
|
|
@@ -214,7 +214,7 @@ async function mergeSessionStartHook() {
|
|
|
214
214
|
const updatedSessionStart = [...cleaned, setupHook];
|
|
215
215
|
const updatedHooks = { ...hooks, SessionStart: updatedSessionStart };
|
|
216
216
|
const updatedSettings = { ...settings, hooks: updatedHooks };
|
|
217
|
-
await (0, promises_1.writeFile)(settingsPath, JSON.stringify(updatedSettings, undefined, 2)
|
|
217
|
+
await (0, promises_1.writeFile)(settingsPath, `${JSON.stringify(updatedSettings, undefined, 2)}\n`, "utf8");
|
|
218
218
|
const action = hasStale || currentCount > 1 ? "Updated" : "Added";
|
|
219
219
|
console.log(`📋 ${action} SessionStart hook in .claude/settings.json`);
|
|
220
220
|
}
|
|
@@ -34,9 +34,11 @@ Structure and write Linear bug reports from evidence that already exists in the
|
|
|
34
34
|
|
|
35
35
|
**Title:** Describes the SYMPTOM, not the cause. Under 70 characters. No bracket prefixes.
|
|
36
36
|
|
|
37
|
-
**
|
|
37
|
+
**Repository:** Always include the repository name in the ticket body. Run `git remote get-url origin | sed 's/\.git$//' | sed 's/.*[:/]\([^/]*\/[^/]*\)$/\1/'` to get the `org/repo` name. For simple bugs, include as a bold inline label. For complex bugs, include in `## Technical Context`.
|
|
38
38
|
|
|
39
|
-
**
|
|
39
|
+
**Simple bug** (<4 details): A paragraph with bold inline labels (**Expected:**, **Actual:**, **Repository:**, etc.). No `##` headers needed.
|
|
40
|
+
|
|
41
|
+
**Complex bug** (multi-service, intermittent, wide impact): Use `## Expected Behavior`, `## Actual Behavior`, `## Steps to Reproduce`, `## Evidence`, `## Technical Context` (include repository — observables only, NOT diagnosis), `## Impact`.
|
|
40
42
|
|
|
41
43
|
**Metadata:** Priority, labels (`bug`), presented BELOW the body. Always ask for team/assignee.
|
|
42
44
|
|
|
@@ -58,3 +60,4 @@ See reference.md for full examples.
|
|
|
58
60
|
| STR invented from assumptions | "Not yet reproduced. Observed via monitoring." |
|
|
59
61
|
| Guessed team assignment | Ask the user — never guess |
|
|
60
62
|
| Bracket title prefixes | Describe the symptom without brackets |
|
|
63
|
+
| Missing repository | Include repo name in ticket body — derive from git remote |
|
|
@@ -27,6 +27,8 @@ Nurses on the mobile app are unable to complete shift bookings. After submitting
|
|
|
27
27
|
|
|
28
28
|
**Actual Behavior:** Spinner runs indefinitely. App must be force-closed.
|
|
29
29
|
|
|
30
|
+
**Repository:** ClipboardHealth/core-utils
|
|
31
|
+
|
|
30
32
|
**Evidence:**
|
|
31
33
|
|
|
32
34
|
- [RUM: session for user 12345 showing hang](https://app.datadoghq.com/rum/...)
|
|
@@ -58,6 +60,8 @@ Not yet reproduced manually. Observed via monitoring.
|
|
|
58
60
|
|
|
59
61
|
## Technical Context
|
|
60
62
|
|
|
63
|
+
**Repository:** ClipboardHealth/core-utils
|
|
64
|
+
|
|
61
65
|
Errors began at 2026-03-12 14:00 UTC. Error logs reference `MongoServerError: connection pool exhausted`. Correlates with deploy at 13:45 UTC.
|
|
62
66
|
|
|
63
67
|
## Impact
|
|
@@ -53,15 +53,17 @@ Before drafting, verify ALL of these. If any fail, bounce back to `interview-fea
|
|
|
53
53
|
|
|
54
54
|
**Title:** Short, imperative, describes the CAPABILITY — not the implementation. Under 70 characters.
|
|
55
55
|
|
|
56
|
+
**Repository:** Always include the repository name in the ticket body. Run `git remote get-url origin | sed 's/\.git$//' | sed 's/.*[:/]\([^/]*\/[^/]*\)$/\1/'` to get the `org/repo` name. For simple features, include as a bold inline label at the end. For complex features, include in `## Context`.
|
|
57
|
+
|
|
56
58
|
**Simple feature** (single user story, <4 acceptance criteria):
|
|
57
|
-
A paragraph stating the problem and who it affects, then acceptance criteria as a checklist. No section headers.
|
|
59
|
+
A paragraph stating the problem and who it affects, then acceptance criteria as a checklist, then repository. No section headers.
|
|
58
60
|
|
|
59
61
|
**Complex feature** (multiple user stories, 4+ AC, or cross-cutting):
|
|
60
62
|
Sections as needed:
|
|
61
63
|
|
|
62
64
|
- `## Problem` — who is affected, what they can't do today, why it matters
|
|
63
65
|
- `## Acceptance Criteria` — observable outcomes checklist
|
|
64
|
-
- `## Context` — links to HLD, related tickets (linking to technical docs is fine; inlining implementation details is not)
|
|
66
|
+
- `## Context` — repository, links to HLD, related tickets (linking to technical docs is fine; inlining implementation details is not)
|
|
65
67
|
- `## Scope` — in/out, if ambiguity exists
|
|
66
68
|
|
|
67
69
|
**Sub-issues** (when decomposed):
|
|
@@ -22,6 +22,8 @@ Workplaces using phone interviews receive a daily interview digest email that is
|
|
|
22
22
|
- [ ] Workplaces using phone interviews do not receive the digest by default
|
|
23
23
|
- [ ] When a workplace switches to phone interviews, the digest is automatically disabled
|
|
24
24
|
|
|
25
|
+
**Repository:** ClipboardHealth/core-utils
|
|
26
|
+
|
|
25
27
|
## Complex Ticket (with sub-issues)
|
|
26
28
|
|
|
27
29
|
**Parent — Title:** Allow workplaces to disable the daily interview digest
|
|
@@ -38,6 +40,10 @@ Workplaces using phone interviews receive a daily interview digest email that is
|
|
|
38
40
|
- [ ] When a workplace switches to phone interviews, the digest is automatically disabled
|
|
39
41
|
- [ ] Only employee admins can change this setting (not workplace admins)
|
|
40
42
|
|
|
43
|
+
### Context
|
|
44
|
+
|
|
45
|
+
**Repository:** ClipboardHealth/core-utils
|
|
46
|
+
|
|
41
47
|
### Scope
|
|
42
48
|
|
|
43
49
|
- **In:** Per-workplace toggle, auto-disable for phone interview workplaces
|
|
@@ -15,3 +15,4 @@ Check every row before showing the draft to the user. If any apply, fix before p
|
|
|
15
15
|
| Parroting technical input | User says "field X", ticket says "field X" | Translate to user-facing language. The ticket reader shouldn't need to know the codebase. |
|
|
16
16
|
| Invented details | Plausible-sounding claims not from conversation or research | Remove. If the detail is needed, bounce back to the interview skill. |
|
|
17
17
|
| No decomposition for multi-outcome work | Two independent user-facing outcomes in one ticket | Split into parent + sub-issues, each describing one deliverable outcome |
|
|
18
|
+
| Missing repository | No repo specified in ticket body | Include repo name — derive from git remote |
|
|
@@ -13,7 +13,7 @@ Draft Linear tech debt tickets that justify _why_ the debt matters — cost to c
|
|
|
13
13
|
|
|
14
14
|
## Process
|
|
15
15
|
|
|
16
|
-
1. **Gather context** — from code, PR comment, conversation, or audit
|
|
16
|
+
1. **Gather context** — from code, PR comment, conversation, or audit. Note how the debt was discovered (see Discovery Context below).
|
|
17
17
|
2. **Analyze the code** — read the actual code. Understand what it does and why it qualifies as debt.
|
|
18
18
|
3. **Classify** — pick a primary debt type (and optional secondary) from classification table in reference.md
|
|
19
19
|
4. **Gather evidence** (driven by classification):
|
|
@@ -29,7 +29,7 @@ Draft Linear tech debt tickets that justify _why_ the debt matters — cost to c
|
|
|
29
29
|
|
|
30
30
|
## Hard Rules
|
|
31
31
|
|
|
32
|
-
- **Debt ticket, not refactoring task.** Document the cost. NEVER include "Proposed Solution", "Suggested Fix", "Acceptance Criteria", or implementation steps. You may describe _ideal state_ (destination) but NOT steps to get there.
|
|
32
|
+
- **Debt ticket, not refactoring task.** Document the cost. NEVER include "Proposed Solution", "Suggested Approach", "Suggested Fix", "Acceptance Criteria", or implementation steps. You may describe _ideal state_ (destination) but NOT steps to get there.
|
|
33
33
|
- **"Impact If Left Unaddressed" is MANDATORY.** What happens in 3-6 months if nobody fixes this? Without this, the ticket is just a complaint.
|
|
34
34
|
- **Always read the code.** Every claim backed by a code reference or data. No vibes.
|
|
35
35
|
- **Justify every rating.** Cite git history, Datadog data, or workaround examples.
|
|
@@ -45,9 +45,13 @@ Draft Linear tech debt tickets that justify _why_ the debt matters — cost to c
|
|
|
45
45
|
|
|
46
46
|
**Title:** Describes the debt, not the fix. Under 70 characters. No bracket prefixes.
|
|
47
47
|
|
|
48
|
-
**
|
|
48
|
+
**Repository:** Always include the repository name in the ticket body. Run `git remote get-url origin | sed 's/\.git$//' | sed 's/.*[:/]\([^/]*\/[^/]*\)$/\1/'` to get the `org/repo` name. For simple debt, include as a bold inline label. For complex debt, include in `## What Is The Debt`.
|
|
49
49
|
|
|
50
|
-
**
|
|
50
|
+
**Discovery Context:** If the debt was discovered while working on a specific ticket, PR, or incident, include that context so reviewers understand how it surfaced. For simple debt, add a sentence (e.g., "Discovered while working on [TICKET-123](link)."). For complex debt, include a `## Discovery Context` section with the originating ticket/PR link and a brief note on how the work revealed the debt. Omit this section only if the debt was found through a standalone audit with no originating ticket.
|
|
51
|
+
|
|
52
|
+
**Simple debt** (single location, clear impact): A paragraph with classification, repository, code references, discovery context (if applicable), and "Impact If Left Unaddressed" inline.
|
|
53
|
+
|
|
54
|
+
**Complex debt** (multi-file, systemic, high-stakes): Use `## What Is The Debt` (include repository), `## Discovery Context` (if applicable — originating ticket/PR and how the work revealed the debt), `## Debt Classification` (type + rated interest/risk with justifications), `## Code References`, `## Evidence`, `## Ideal State` (destination, not route), `## Impact If Left Unaddressed`.
|
|
51
55
|
|
|
52
56
|
**Metadata:** Priority, labels (`technical-debt`), presented BELOW the body. Always ask for team/assignee.
|
|
53
57
|
|
|
@@ -55,15 +59,18 @@ See reference.md for classification tables, rating framework, and full examples.
|
|
|
55
59
|
|
|
56
60
|
## Red Flags — Self-Review Before Presenting
|
|
57
61
|
|
|
58
|
-
| Anti-Pattern | Fix
|
|
59
|
-
| --------------------------------- |
|
|
60
|
-
| Reads like a refactoring task | Rewrite to document the cost of the debt, not the fix
|
|
61
|
-
| Has "Proposed Solution" section | Delete. Describe ideal state instead.
|
|
62
|
-
| Has "
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
| No
|
|
68
|
-
|
|
|
69
|
-
|
|
|
62
|
+
| Anti-Pattern | Fix |
|
|
63
|
+
| --------------------------------- | --------------------------------------------------------- |
|
|
64
|
+
| Reads like a refactoring task | Rewrite to document the cost of the debt, not the fix |
|
|
65
|
+
| Has "Proposed Solution" section | Delete. Describe ideal state instead. |
|
|
66
|
+
| Has "Suggested Approach" section | Delete. Describe ideal state instead. |
|
|
67
|
+
| Has "Acceptance Criteria" | Delete. This is a debt ticket, not a task. |
|
|
68
|
+
| No code references | Add specific file paths and line numbers |
|
|
69
|
+
| Unjustified ratings | Cite git frequency, Datadog data, or workaround examples |
|
|
70
|
+
| Aesthetic complaints as debt | Explain the concrete cost or don't file the ticket |
|
|
71
|
+
| No "Impact If Left Unaddressed" | Always include — this gets the ticket prioritized |
|
|
72
|
+
| No Datadog for perf/reliability | You MUST search Datadog for these types |
|
|
73
|
+
| Forced Datadog on maintainability | Only for performance/reliability/scalability |
|
|
74
|
+
| Guessed team assignment | Ask the user |
|
|
75
|
+
| Missing repository | Include repo name in ticket body — derive from git remote |
|
|
76
|
+
| Missing discovery context | If debt was found during ticket/PR work, link it |
|
|
@@ -37,6 +37,8 @@ Each: High/Medium/Low with a one-line justification backed by evidence.
|
|
|
37
37
|
|
|
38
38
|
**Title:** Shift matching query scans full collection on every request
|
|
39
39
|
|
|
40
|
+
**Repository:** ClipboardHealth/core-utils. Discovered while working on [ENG-4521](https://linear.app/clipboard-health/issue/ENG-4521) (shift booking latency improvements) — investigation revealed the missing index as a separate concern from the ticket's scope.
|
|
41
|
+
|
|
40
42
|
The shift matching query in `src/services/booking/shiftMatcher.ts:142` executes `find({ facility, status: 'open' })` without an index on the `facility` field. Every matching request scans ~200k documents instead of the ~50 that match.
|
|
41
43
|
|
|
42
44
|
**Type:** Performance | **Interest:** High — 847 requests/day hit this path. p99 latency is 4.2s vs ~120ms baseline for indexed queries ([APM: shift matching latency](https://app.datadoghq.com/apm/...)). **Incident Risk:** Medium — a traffic spike during peak booking could exhaust the connection pool. **Velocity Risk:** Low — code is stable, rarely modified.
|
|
@@ -55,8 +57,14 @@ Suggested metadata: Priority: High
|
|
|
55
57
|
|
|
56
58
|
#### What Is The Debt
|
|
57
59
|
|
|
60
|
+
**Repository:** ClipboardHealth/core-utils
|
|
61
|
+
|
|
58
62
|
Four cron jobs (`DailyDigestCron`, `ShiftReminderCron`, `CredentialExpiryCron`, `TimesheetReminderCron`) each implement their own notification dispatch: recipient resolution, template selection, channel routing, and retry handling. The implementations are nearly identical but have diverged — each has different retry behavior and error handling, making it impossible to reason about notification reliability as a whole.
|
|
59
63
|
|
|
64
|
+
#### Discovery Context
|
|
65
|
+
|
|
66
|
+
Discovered while implementing push notification support for [ENG-3891](https://linear.app/clipboard-health/issue/ENG-3891). Adding the new channel required duplicating dispatch logic into a fifth cron job, revealing the extent of the divergence.
|
|
67
|
+
|
|
60
68
|
#### Classification
|
|
61
69
|
|
|
62
70
|
- **Type:** Maintainability (primary), Reliability (secondary)
|