@runecraft/grimoire 1.0.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/catalog.json +9 -0
  4. package/dist/grimoire.js +1758 -0
  5. package/package.json +54 -0
  6. package/references/definition-of-done.md +67 -0
  7. package/references/testing-patterns.md +260 -0
  8. package/skills/code-review-and-quality/README.md +13 -0
  9. package/skills/code-review-and-quality/SKILL.md +389 -0
  10. package/skills/code-simplification/README.md +13 -0
  11. package/skills/code-simplification/SKILL.md +338 -0
  12. package/skills/debugging-and-error-recovery/README.md +13 -0
  13. package/skills/debugging-and-error-recovery/SKILL.md +343 -0
  14. package/skills/debugging-and-error-recovery/scripts/__pycache__/triage_state.cpython-314.pyc +0 -0
  15. package/skills/debugging-and-error-recovery/scripts/triage_state.py +206 -0
  16. package/skills/deprecation-and-migration/README.md +13 -0
  17. package/skills/deprecation-and-migration/SKILL.md +248 -0
  18. package/skills/deprecation-and-migration/scripts/__pycache__/migration_tracker.cpython-314.pyc +0 -0
  19. package/skills/deprecation-and-migration/scripts/migration_tracker.py +237 -0
  20. package/skills/doubt-driven-development/README.md +13 -0
  21. package/skills/doubt-driven-development/SKILL.md +251 -0
  22. package/skills/git-commit-learning/.skill-meta.json +14 -0
  23. package/skills/git-commit-learning/README.md +205 -0
  24. package/skills/git-commit-learning/SKILL.md +435 -0
  25. package/skills/git-commit-learning/references/commit-patterns.md +595 -0
  26. package/skills/git-worktree/README.md +13 -0
  27. package/skills/git-worktree/SKILL.md +220 -0
  28. package/skills/idea-refine/README.md +13 -0
  29. package/skills/idea-refine/SKILL.md +186 -0
  30. package/skills/interview-me/README.md +13 -0
  31. package/skills/interview-me/SKILL.md +233 -0
  32. package/skills/linkedin-audit/SKILL.md +98 -0
  33. package/skills/linkedin-audit/references/dashboard-spec.md +43 -0
  34. package/skills/memory-management/README.md +13 -0
  35. package/skills/memory-management/SKILL.md +198 -0
  36. package/skills/security-and-hardening/README.md +13 -0
  37. package/skills/security-and-hardening/SKILL.md +472 -0
  38. package/skills/shipping-and-launch/README.md +13 -0
  39. package/skills/shipping-and-launch/SKILL.md +317 -0
  40. package/skills/skill-forge/README.md +153 -0
  41. package/skills/skill-forge/SKILL.md +291 -0
  42. package/skills/skill-forge/assets/SKILL.template.md +73 -0
  43. package/skills/skill-forge/references/authoring-patterns.md +249 -0
  44. package/skills/skill-forge/references/description-optimization.md +171 -0
  45. package/skills/skill-forge/references/output-evaluation.md +276 -0
  46. package/skills/skill-forge/references/scripts-guide.md +232 -0
  47. package/skills/skill-forge/references/spec.md +175 -0
  48. package/skills/skill-forge/scripts/validate.py +536 -0
  49. package/skills/spec-driven/.skill-meta.json +14 -0
  50. package/skills/spec-driven/README.md +335 -0
  51. package/skills/spec-driven/SKILL.md +174 -0
  52. package/skills/spec-driven/references/code-analysis.md +98 -0
  53. package/skills/spec-driven/references/coding-principles.md +56 -0
  54. package/skills/spec-driven/references/context-limits.md +31 -0
  55. package/skills/spec-driven/references/design.md +199 -0
  56. package/skills/spec-driven/references/discuss.md +136 -0
  57. package/skills/spec-driven/references/implement.md +425 -0
  58. package/skills/spec-driven/references/lessons.md +113 -0
  59. package/skills/spec-driven/references/memory.md +126 -0
  60. package/skills/spec-driven/references/specify.md +210 -0
  61. package/skills/spec-driven/references/sub-agents.md +96 -0
  62. package/skills/spec-driven/references/tasks.md +484 -0
  63. package/skills/spec-driven/references/validate.md +350 -0
  64. package/skills/spec-driven/scripts/__pycache__/lessons.cpython-314.pyc +0 -0
  65. package/skills/spec-driven/scripts/lessons.py +370 -0
  66. package/skills/spec-loop/README.md +36 -0
  67. package/skills/spec-loop/SKILL.md +61 -0
  68. package/skills/test-driven-development/README.md +13 -0
  69. package/skills/test-driven-development/SKILL.md +388 -0
  70. package/skills/typescript-patterns/README.md +13 -0
  71. package/skills/typescript-patterns/SKILL.md +346 -0
  72. package/skills/using-agent-skills/README.md +13 -0
  73. package/skills/using-agent-skills/SKILL.md +187 -0
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ triage_state.py — deterministic bookkeeping for one active debug session.
4
+
5
+ Tracks step progress and evidence trail through the 6-phase triage loop:
6
+ reproduce → localize → reduce → fix → guard → verify.
7
+
8
+ Canonical state: .debug/<session-id>/state.json (machine-owned — do NOT hand-edit)
9
+ Rendered view: .debug/<session-id>/TRIAGE.md (regenerated on every write)
10
+
11
+ Pure standard library. No dependencies. Run from the project root (the dir that
12
+ contains .debug/), or pass --root.
13
+
14
+ Commands:
15
+ start Begin a new debug session.
16
+ log-step Record completion of one triage step.
17
+ status Print current step and evidence trail.
18
+ close Mark the session resolved.
19
+
20
+ Exit codes: 0 ok, 2 usage/validation error (e.g. missing grounding).
21
+ """
22
+
23
+ import argparse
24
+ import datetime as _dt
25
+ import json
26
+ import os
27
+ import sys
28
+
29
+ STEPS = ("reproduce", "localize", "reduce", "fix", "guard", "verify")
30
+
31
+
32
+ def _now():
33
+ return _dt.datetime.now(_dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
34
+
35
+
36
+ def _debug_dir(root):
37
+ return os.path.join(root, ".debug")
38
+
39
+
40
+ def _session_dir(root, session_id):
41
+ return os.path.join(_debug_dir(root), session_id)
42
+
43
+
44
+ def _store_path(root, session_id):
45
+ return os.path.join(_session_dir(root, session_id), "state.json")
46
+
47
+
48
+ def _render_path(root, session_id):
49
+ return os.path.join(_session_dir(root, session_id), "TRIAGE.md")
50
+
51
+
52
+ def _load(root, session_id):
53
+ path = _store_path(root, session_id)
54
+ if not os.path.exists(path):
55
+ return None
56
+ with open(path, "r", encoding="utf-8") as f:
57
+ return json.load(f)
58
+
59
+
60
+ def _save(root, session_id, data):
61
+ os.makedirs(_session_dir(root, session_id), exist_ok=True)
62
+ with open(_store_path(root, session_id), "w", encoding="utf-8") as f:
63
+ json.dump(data, f, indent=2, ensure_ascii=False)
64
+ f.write("\n")
65
+ _render(root, session_id, data)
66
+
67
+
68
+ def _ground(root, session_id):
69
+ data = _load(root, session_id)
70
+ if data is None:
71
+ print(f"ERROR: no active session '{session_id}'. Run 'start' first.", file=sys.stderr)
72
+ return None
73
+ return data
74
+
75
+
76
+ def _render(root, session_id, data):
77
+ lines = []
78
+ lines.append(f"# Triage Session: {session_id}")
79
+ lines.append("")
80
+ lines.append("> Machine-owned. Do NOT hand-edit. Changes are overwritten on the next `triage_state.py` write.")
81
+ lines.append(f"> Canonical state lives in `.debug/{session_id}/state.json`.")
82
+ lines.append("")
83
+ lines.append(f"**Description:** {data['description']}")
84
+ lines.append(f"**Status:** {data['status']}")
85
+ lines.append(f"**Created:** {data.get('created', '—')}")
86
+ if data.get("closed"):
87
+ lines.append(f"**Closed:** {data['closed']}")
88
+ lines.append("")
89
+ lines.append("## Steps")
90
+ lines.append("")
91
+ steps = data.get("steps", [])
92
+ if not steps:
93
+ lines.append("_none_")
94
+ lines.append("")
95
+ else:
96
+ for s in steps:
97
+ lines.append(f"### {s['step']}")
98
+ lines.append(f"- **note:** {s['note']}")
99
+ lines.append(f"- **timestamp:** {s['timestamp']}")
100
+ lines.append("")
101
+ with open(_render_path(root, session_id), "w", encoding="utf-8") as f:
102
+ f.write("\n".join(lines).rstrip() + "\n")
103
+
104
+
105
+ # ----------------------------- commands -----------------------------
106
+
107
+ def cmd_start(root, args):
108
+ session_id = args.session_id
109
+ if _load(root, session_id) is not None:
110
+ print(f"ERROR: session '{session_id}' already exists. Use 'close' first or pick a different id.", file=sys.stderr)
111
+ return 2
112
+ now = _now()
113
+ data = {
114
+ "session_id": session_id,
115
+ "description": args.description,
116
+ "status": "open",
117
+ "steps": [],
118
+ "created": now,
119
+ }
120
+ _save(root, session_id, data)
121
+ print(f"STARTED session '{session_id}': {args.description}")
122
+ return 0
123
+
124
+
125
+ def cmd_log_step(root, args):
126
+ session_id = args.session_id
127
+ data = _ground(root, session_id)
128
+ if data is None:
129
+ return 2
130
+ if args.step not in STEPS:
131
+ print(f"ERROR: --step must be one of {sorted(STEPS)}", file=sys.stderr)
132
+ return 2
133
+ if not (args.note or "").strip():
134
+ print("ERROR: --note is required (one-line evidence or outcome).", file=sys.stderr)
135
+ return 2
136
+ note = args.note.strip()
137
+ data.setdefault("steps", []).append({
138
+ "step": args.step,
139
+ "note": note,
140
+ "timestamp": _now(),
141
+ })
142
+ _save(root, session_id, data)
143
+ print(f"LOGGED '{args.step}' step in session '{session_id}': {note}")
144
+ return 0
145
+
146
+
147
+ def cmd_status(root, args):
148
+ session_id = args.session_id
149
+ data = _ground(root, session_id)
150
+ if data is None:
151
+ return 2
152
+ steps = data.get("steps", [])
153
+ last = steps[-1]["step"] if steps else "(none)"
154
+ print(f"session: {session_id}")
155
+ print(f"description: {data['description']}")
156
+ print(f"status: {data['status']}")
157
+ print(f"current step: {last}")
158
+ print(f"steps completed: {len(steps)}")
159
+ for s in steps:
160
+ print(f" {s['step']}: {s['note']}")
161
+ return 0
162
+
163
+
164
+ def cmd_close(root, args):
165
+ session_id = args.session_id
166
+ data = _ground(root, session_id)
167
+ if data is None:
168
+ return 2
169
+ data["status"] = "closed"
170
+ data["closed"] = _now()
171
+ _save(root, session_id, data)
172
+ print(f"CLOSED session '{session_id}'")
173
+ return 0
174
+
175
+
176
+ def main(argv=None):
177
+ p = argparse.ArgumentParser(prog="triage_state.py", description="Deterministic debug session bookkeeping.")
178
+ p.add_argument("--root", default=".", help="Project root containing .debug/ (default: current dir)")
179
+ sub = p.add_subparsers(dest="cmd", required=True)
180
+
181
+ sp = sub.add_parser("start", help="Begin a new debug session")
182
+ sp.add_argument("--session-id", required=True, help="Session identifier")
183
+ sp.add_argument("--description", required=True, help="Short bug description")
184
+ sp.set_defaults(fn=cmd_start)
185
+
186
+ sp = sub.add_parser("log-step", help="Record completion of one triage step")
187
+ sp.add_argument("--session-id", required=True, help="Session identifier")
188
+ sp.add_argument("--step", required=True, choices=sorted(STEPS), help="Triage step completed")
189
+ sp.add_argument("--note", required=True, help="One-line evidence or outcome note")
190
+ sp.set_defaults(fn=cmd_log_step)
191
+
192
+ sp = sub.add_parser("status", help="Print current step and evidence trail")
193
+ sp.add_argument("--session-id", required=True, help="Session identifier")
194
+ sp.set_defaults(fn=cmd_status)
195
+
196
+ sp = sub.add_parser("close", help="Mark the session resolved")
197
+ sp.add_argument("--session-id", required=True, help="Session identifier")
198
+ sp.set_defaults(fn=cmd_close)
199
+
200
+ args = p.parse_args(argv)
201
+ root = os.path.abspath(args.root)
202
+ return args.fn(root, args)
203
+
204
+
205
+ if __name__ == "__main__":
206
+ raise SystemExit(main())
@@ -0,0 +1,13 @@
1
+ # deprecation-and-migration
2
+
3
+ Retire old systems, APIs, and features. Migrate users safely. Treats code as liability, not asset.
4
+
5
+ | Field | Value |
6
+ |-------|-------|
7
+ | Version | 1.0.0 |
8
+ | Trigger | `/deprecate`, `/migrate`, "retire this", "sunset feature", "code is liability" |
9
+ | PT trigger | `/depreciar`, `/migrar`, "aposentar", "código como passivo" |
10
+
11
+ **Do not use for** pure code quality cleanup without user impact (use `/simplify`) or new feature implementation.
12
+
13
+ See [SKILL.md](SKILL.md) for the full process.
@@ -0,0 +1,248 @@
1
+ ---
2
+ name: deprecation-and-migration
3
+ description: >
4
+ Manages deprecation and migration of old systems, APIs, or features — distinguishing compulsory vs
5
+ advisory changes and treating code as liability. Use when removing dead code, retiring APIs, or
6
+ migrating users between implementations.
7
+ EN triggers: /deprecate, /migrate, retire this, sunset feature, "code is liability", compulsory vs advisory.
8
+ PT triggers: /depreciar, /migrar, aposentar, descontinuar, código como passivo.
9
+ Do NOT use for: pure code quality cleanup without user impact (use /simplify), or new feature
10
+ implementation.
11
+ license: CC-BY-4.0
12
+ ---
13
+
14
+ # Deprecation and Migration
15
+
16
+ ## Overview
17
+
18
+ Code is a liability, not an asset. Every line of code has ongoing maintenance cost — bugs to fix, dependencies to update, security patches to apply, and new engineers to onboard. Deprecation is the discipline of removing code that no longer earns its keep, and migration is the process of moving users safely from the old to the new.
19
+
20
+ Most engineering organizations are good at building things. Few are good at removing them. This skill addresses that gap.
21
+
22
+ ## When to Use
23
+
24
+ - Replacing an old system, API, or library with a new one
25
+ - Sunsetting a feature that's no longer needed
26
+ - Consolidating duplicate implementations
27
+ - Removing dead code that nobody owns but everybody depends on
28
+ - Planning the lifecycle of a new system (deprecation planning starts at design time)
29
+ - Deciding whether to maintain a legacy system or invest in migration
30
+
31
+ ## Core Principles
32
+
33
+ ### Code Is a Liability
34
+
35
+ Every line of code has ongoing cost: it needs tests, documentation, security patches, dependency updates, and mental overhead for anyone working nearby. The value of code is the functionality it provides, not the code itself. When the same functionality can be provided with less code, less complexity, or better abstractions — the old code should go.
36
+
37
+ ### Hyrum's Law Makes Removal Hard
38
+
39
+ With enough users, every observable behavior becomes depended on — including bugs, timing quirks, and undocumented side effects. This is why deprecation requires active migration, not just announcement. Users can't "just switch" when they depend on behaviors the replacement doesn't replicate.
40
+
41
+ ### Deprecation Planning Starts at Design Time
42
+
43
+ When building something new, ask: "How would we remove this in 3 years?" Systems designed with clean interfaces, feature flags, and minimal surface area are easier to deprecate than systems that leak implementation details everywhere.
44
+
45
+ ## The Deprecation Decision
46
+
47
+ Before deprecating anything, answer these questions:
48
+
49
+ ```
50
+ 1. Does this system still provide unique value?
51
+ → If yes, maintain it. If no, proceed.
52
+
53
+ 2. How many users/consumers depend on it?
54
+ → Quantify the migration scope.
55
+
56
+ 3. Does a replacement exist?
57
+ → If no, build the replacement first. Don't deprecate without an alternative.
58
+
59
+ 4. What's the migration cost for each consumer?
60
+ → If trivially automated, do it. If manual and high-effort, weigh against maintenance cost.
61
+
62
+ 5. What's the ongoing maintenance cost of NOT deprecating?
63
+ → Security risk, engineer time, opportunity cost of complexity.
64
+ ```
65
+
66
+ ## Compulsory vs Advisory Deprecation
67
+
68
+ | Type | When to Use | Mechanism |
69
+ |------|-------------|-----------|
70
+ | **Advisory** | Migration is optional, old system is stable | Warnings, documentation, nudges. Users migrate on their own timeline. |
71
+ | **Compulsory** | Old system has security issues, blocks progress, or maintenance cost is unsustainable | Hard deadline. Old system will be removed by date X. Provide migration tooling. |
72
+
73
+ **Default to advisory.** Use compulsory only when the maintenance cost or risk justifies forcing migration. Compulsory deprecation requires providing migration tooling, documentation, and support — you can't just announce a deadline.
74
+
75
+ ## The Migration Process
76
+
77
+ ### Step 1: Build the Replacement
78
+
79
+ Don't deprecate without a working alternative. The replacement must:
80
+
81
+ - Cover all critical use cases of the old system
82
+ - Have documentation and migration guides
83
+ - Be proven in production (not just "theoretically better")
84
+
85
+ ### Step 2: Announce and Document
86
+
87
+ ```markdown
88
+ ## Deprecation Notice: OldService
89
+
90
+ **Status:** Deprecated as of 2025-03-01
91
+ **Replacement:** NewService (see migration guide below)
92
+ **Removal date:** Advisory — no hard deadline yet
93
+ **Reason:** OldService requires manual scaling and lacks observability.
94
+ NewService handles both automatically.
95
+
96
+ ### Migration Guide
97
+ 1. Replace `import { client } from 'old-service'` with `import { client } from 'new-service'`
98
+ 2. Update configuration (see examples below)
99
+ 3. Run the migration verification script: `npx migrate-check`
100
+ ```
101
+
102
+ ### Step 3: Migrate Incrementally
103
+
104
+ Migrate consumers one at a time, not all at once. For each consumer:
105
+
106
+ ```
107
+ 1. Identify all touchpoints with the deprecated system
108
+ 2. Update to use the replacement
109
+ 3. Verify behavior matches (tests, integration checks)
110
+ 4. Remove references to the old system
111
+ 5. Confirm no regressions
112
+ ```
113
+
114
+ **The Churn Rule:** If you own the infrastructure being deprecated, you are responsible for migrating your users — or providing backward-compatible updates that require no migration. Don't announce deprecation and leave users to figure it out.
115
+
116
+ ### Step 4: Remove the Old System
117
+
118
+ Only after all consumers have migrated:
119
+
120
+ ```
121
+ 1. Verify zero active usage (metrics, logs, dependency analysis)
122
+ 2. Remove the code
123
+ 3. Remove associated tests, documentation, and configuration
124
+ 4. Remove the deprecation notices
125
+ 5. Celebrate — removing code is an achievement
126
+ ```
127
+
128
+ ## Migration Tracking
129
+
130
+ Track migration consumers deterministically using `scripts/migration_tracker.py`. This avoids ad-hoc checklists and keeps consumer status visible across sessions.
131
+
132
+ ### WRITE — record consumer state
133
+
134
+ When the consumer list is first enumerated during [The Deprecation Decision](#the-deprecation-decision), add each consumer:
135
+
136
+ ```bash
137
+ python3 scripts/migration_tracker.py add-consumer --slug <slug> --consumer <name> --status <pending|migrating|done>
138
+ ```
139
+
140
+ As each consumer completes migration in [Step 3: Migrate Incrementally](#step-3-migrate-incrementally), mark it:
141
+
142
+ ```bash
143
+ python3 scripts/migration_tracker.py mark-migrated --slug <slug> --consumer <name> --note <text>
144
+ ```
145
+
146
+ ### READ — query migration progress
147
+
148
+ ```bash
149
+ # Aggregate counts (pending / migrating / done)
150
+ python3 scripts/migration_tracker.py status --slug <slug>
151
+
152
+ # List consumers that still need migration
153
+ python3 scripts/migration_tracker.py list-pending --slug <slug>
154
+ ```
155
+
156
+ Read status before [Step 4: Remove the Old System](#step-4-remove-the-old-system) to confirm zero pending consumers.
157
+
158
+ ### Fallback when code execution is unavailable
159
+
160
+ Some harnesses cannot run Python. Only then: maintain `.migrations/<slug>/STATUS.md` by hand, tracking consumer name, status, and migration notes. **This path is degraded**: hand bookkeeping is the failure mode this tool exists to avoid, so prefer the script wherever a code tool exists. State once in chat that you are in the no-script fallback so the user knows accounting is best-effort.
161
+
162
+ ## Migration Patterns
163
+
164
+ ### Strangler Pattern
165
+
166
+ Run old and new systems in parallel. Route traffic incrementally from old to new. When the old system handles 0% of traffic, remove it.
167
+
168
+ ```
169
+ Phase 1: New system handles 0%, old handles 100%
170
+ Phase 2: New system handles 10% (canary)
171
+ Phase 3: New system handles 50%
172
+ Phase 4: New system handles 100%, old system idle
173
+ Phase 5: Remove old system
174
+ ```
175
+
176
+ ### Adapter Pattern
177
+
178
+ Create an adapter that translates calls from the old interface to the new implementation. Consumers keep using the old interface while you migrate the backend.
179
+
180
+ ```typescript
181
+ // Adapter: old interface, new implementation
182
+ class LegacyTaskService implements OldTaskAPI {
183
+ constructor(private newService: NewTaskService) {}
184
+
185
+ // Old method signature, delegates to new implementation
186
+ getTask(id: number): OldTask {
187
+ const task = this.newService.findById(String(id));
188
+ return this.toOldFormat(task);
189
+ }
190
+ }
191
+ ```
192
+
193
+ ### Feature Flag Migration
194
+
195
+ Use feature flags to switch consumers from old to new system one at a time:
196
+
197
+ ```typescript
198
+ function getTaskService(userId: string): TaskService {
199
+ if (featureFlags.isEnabled('new-task-service', { userId })) {
200
+ return new NewTaskService();
201
+ }
202
+ return new LegacyTaskService();
203
+ }
204
+ ```
205
+
206
+ ## Zombie Code
207
+
208
+ Zombie code is code that nobody owns but everybody depends on. It's not actively maintained, has no clear owner, and accumulates security vulnerabilities and compatibility issues. Signs:
209
+
210
+ - No commits in 6+ months but active consumers exist
211
+ - No assigned maintainer or team
212
+ - Failing tests that nobody fixes
213
+ - Dependencies with known vulnerabilities that nobody updates
214
+ - Documentation that references systems that no longer exist
215
+
216
+ **Response:** Either assign an owner and maintain it properly, or deprecate it with a concrete migration plan. Zombie code cannot stay in limbo — it either gets investment or removal.
217
+
218
+ ## Common Rationalizations
219
+
220
+ | Rationalization | Reality |
221
+ |---|---|
222
+ | "It still works, why remove it?" | Working code that nobody maintains accumulates security debt and complexity. Maintenance cost grows silently. |
223
+ | "Someone might need it later" | If it's needed later, it can be rebuilt. Keeping unused code "just in case" costs more than rebuilding. |
224
+ | "The migration is too expensive" | Compare migration cost to ongoing maintenance cost over 2-3 years. Migration is usually cheaper long-term. |
225
+ | "We'll deprecate it after we finish the new system" | Deprecation planning starts at design time. By the time the new system is done, you'll have new priorities. Plan now. |
226
+ | "Users will migrate on their own" | They won't. Provide tooling, documentation, and incentives — or do the migration yourself (the Churn Rule). |
227
+ | "We can maintain both systems indefinitely" | Two systems doing the same thing is double the maintenance, testing, documentation, and onboarding cost. |
228
+
229
+ ## Red Flags
230
+
231
+ - Deprecated systems with no replacement available
232
+ - Deprecation announcements with no migration tooling or documentation
233
+ - "Soft" deprecation that's been advisory for years with no progress
234
+ - Zombie code with no owner and active consumers
235
+ - New features added to a deprecated system (invest in the replacement instead)
236
+ - Deprecation without measuring current usage
237
+ - Removing code without verifying zero active consumers
238
+
239
+ ## Verification
240
+
241
+ After completing a deprecation:
242
+
243
+ - [ ] Replacement is production-proven and covers all critical use cases
244
+ - [ ] Migration guide exists with concrete steps and examples
245
+ - [ ] All active consumers have been migrated (verified by metrics/logs)
246
+ - [ ] Old code, tests, documentation, and configuration are fully removed
247
+ - [ ] No references to the deprecated system remain in the codebase
248
+ - [ ] Deprecation notices are removed (they served their purpose)