claude-dev-env 1.83.0 → 1.85.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 (186) hide show
  1. package/_shared/pr-loop/audit-contract.md +24 -12
  2. package/_shared/pr-loop/scripts/_claude_permissions_common.py +16 -5
  3. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
  4. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -1
  5. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +8 -0
  6. package/_shared/pr-loop/scripts/reviews_disabled.py +2 -0
  7. package/_shared/pr-loop/scripts/terminology_sweep.py +85 -39
  8. package/_shared/pr-loop/scripts/tests/test__claude_permissions_common.py +212 -0
  9. package/_shared/pr-loop/scripts/tests/test_agent_config_carveout.py +18 -0
  10. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +18 -0
  11. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +37 -0
  12. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +14 -0
  13. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +94 -4
  14. package/agents/clean-coder.md +3 -0
  15. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
  16. package/bin/install.mjs +16 -8
  17. package/bin/install.test.mjs +17 -6
  18. package/commands/CLAUDE.md +0 -1
  19. package/docs/CODE_RULES.md +1 -1
  20. package/hooks/blocking/CLAUDE.md +0 -4
  21. package/hooks/blocking/claude_md_orphan_file_blocker.py +1 -1
  22. package/hooks/blocking/code_rules_constants_config.py +5 -0
  23. package/hooks/blocking/code_rules_docstrings.py +133 -19
  24. package/hooks/blocking/code_rules_enforcer.py +4 -0
  25. package/hooks/blocking/code_rules_imports_logging.py +10 -6
  26. package/hooks/blocking/code_rules_magic_values.py +5 -0
  27. package/hooks/blocking/code_rules_naming_collection.py +15 -8
  28. package/hooks/blocking/code_rules_paired_test.py +3 -2
  29. package/hooks/blocking/code_rules_shared.py +34 -0
  30. package/hooks/blocking/code_rules_string_magic.py +1 -1
  31. package/hooks/blocking/code_rules_unused_imports.py +2 -2
  32. package/hooks/blocking/duplicate_rmtree_helper_blocker.py +4 -4
  33. package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +29 -0
  34. package/hooks/blocking/test_code_rules_enforcer_docstring_prose_wall_illustration.py +197 -0
  35. package/hooks/blocking/test_code_rules_enforcer_docstring_runon_sentence.py +27 -0
  36. package/hooks/blocking/test_code_rules_enforcer_naive_datetime.py +24 -0
  37. package/hooks/blocking/test_code_rules_enforcer_split_constants_config.py +33 -0
  38. package/hooks/blocking/test_code_rules_enforcer_split_shared.py +23 -0
  39. package/hooks/blocking/test_code_rules_magic_values.py +54 -0
  40. package/hooks/blocking/test_duplicate_rmtree_helper_blocker.py +0 -6
  41. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +184 -0
  42. package/hooks/blocking/test_shared_stdin_adoption.py +5 -30
  43. package/hooks/hooks_constants/CLAUDE.md +0 -3
  44. package/hooks/hooks_constants/blocking_check_limits.py +4 -0
  45. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
  46. package/hooks/hooks_constants/duplicate_rmtree_helper_blocker_constants.py +0 -1
  47. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -5
  48. package/hooks/validation/post_tool_use_dispatcher.py +1 -1
  49. package/hooks/validation/test_post_tool_use_dispatcher.py +51 -35
  50. package/hooks/workflow/CLAUDE.md +2 -8
  51. package/package.json +1 -1
  52. package/rules/CLAUDE.md +1 -1
  53. package/rules/docstring-prose-matches-implementation.md +1 -1
  54. package/rules/env-var-table-code-drift.md +1 -1
  55. package/rules/package-inventory-stale-entry.md +1 -1
  56. package/rules/paired-test-coverage.md +1 -1
  57. package/rules/plain-illustrative-docstrings.md +35 -1
  58. package/skills/CLAUDE.md +6 -1
  59. package/skills/_shared/pr-loop/CLAUDE.md +1 -0
  60. package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -0
  61. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -0
  62. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +45 -0
  63. package/skills/_shared/pr-loop/scripts/test_write_handoff.py +201 -0
  64. package/skills/_shared/pr-loop/scripts/write_handoff.py +309 -0
  65. package/skills/autoconverge/SKILL.md +82 -58
  66. package/skills/autoconverge/reference/closing-report.md +6 -6
  67. package/skills/autoconverge/reference/convergence.md +17 -15
  68. package/skills/autoconverge/reference/gotchas.md +6 -3
  69. package/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +2 -9
  70. package/skills/autoconverge/workflow/converge.contract.test.mjs +87 -13
  71. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +1 -1
  72. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +16 -9
  73. package/skills/autoconverge/workflow/converge.mjs +71 -74
  74. package/skills/autoconverge/workflow/render_report.py +7 -11
  75. package/skills/bugteam/CLAUDE.md +1 -1
  76. package/skills/bugteam/PROMPTS.md +7 -6
  77. package/skills/bugteam/SKILL.md +25 -72
  78. package/skills/bugteam/reference/CLAUDE.md +1 -3
  79. package/skills/bugteam/reference/README.md +1 -1
  80. package/skills/bugteam/reference/audit-and-teammates.md +1 -1
  81. package/skills/bugteam/reference/obstacles/fix-publish-summary.md +1 -1
  82. package/skills/bugteam/reference/team-setup.md +8 -7
  83. package/skills/bugteam/scripts/CLAUDE.md +0 -6
  84. package/skills/bugteam/scripts/README.md +0 -4
  85. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +0 -1
  86. package/skills/code/SKILL.md +2 -0
  87. package/skills/copilot-review/CLAUDE.md +1 -1
  88. package/skills/copilot-review/SKILL.md +25 -23
  89. package/skills/findbugs/CLAUDE.md +2 -2
  90. package/skills/findbugs/SKILL.md +22 -83
  91. package/skills/fixbugs/SKILL.md +2 -4
  92. package/skills/log-audit/CLAUDE.md +20 -0
  93. package/skills/log-audit/SKILL.md +68 -0
  94. package/skills/log-audit/reference/CLAUDE.md +9 -0
  95. package/skills/log-audit/reference/charter.md +52 -0
  96. package/skills/log-audit/scripts/CLAUDE.md +27 -0
  97. package/skills/log-audit/scripts/cluster_recurrences.py +261 -0
  98. package/skills/log-audit/scripts/collect_log_window.py +199 -0
  99. package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +12 -0
  100. package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +23 -0
  101. package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +24 -0
  102. package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +49 -0
  103. package/skills/log-audit/scripts/mine_copilot_findings.py +302 -0
  104. package/skills/log-audit/scripts/test_cluster_recurrences.py +160 -0
  105. package/skills/log-audit/scripts/test_collect_log_window.py +111 -0
  106. package/skills/log-audit/scripts/test_mine_copilot_findings.py +126 -0
  107. package/skills/monitor-open-prs/SKILL.md +2 -2
  108. package/skills/post-audit-findings/SKILL.md +84 -0
  109. package/skills/pr-converge/CLAUDE.md +2 -0
  110. package/skills/pr-converge/SKILL.md +99 -60
  111. package/skills/pr-converge/reference/CLAUDE.md +1 -1
  112. package/skills/pr-converge/reference/convergence-gates.md +16 -19
  113. package/skills/pr-converge/reference/examples.md +5 -5
  114. package/skills/pr-converge/reference/fix-protocol.md +16 -43
  115. package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +1 -1
  116. package/skills/pr-converge/reference/per-tick.md +24 -45
  117. package/skills/pr-converge/reference/state-schema.md +27 -0
  118. package/skills/pr-converge/scripts/README.md +3 -5
  119. package/skills/pr-fix-protocol/SKILL.md +70 -0
  120. package/skills/pr-loop-lifecycle/SKILL.md +73 -0
  121. package/skills/{bugteam → pr-loop-lifecycle}/reference/teardown-publish-permissions.md +22 -24
  122. package/skills/pr-scope-resolve/SKILL.md +48 -0
  123. package/skills/qbug/CLAUDE.md +4 -4
  124. package/skills/qbug/SKILL.md +46 -144
  125. package/skills/qbug/test_qbug_skill_audit_schema.py +2 -2
  126. package/skills/qbug/test_qbug_skill_post_fix_audit.py +1 -1
  127. package/skills/reviewer-gates/SKILL.md +96 -0
  128. package/skills/session-log/CLAUDE.md +7 -7
  129. package/skills/session-log/SKILL.md +27 -44
  130. package/skills/test_markdown_link_integrity.py +103 -0
  131. package/commands/doc-gist.md +0 -16
  132. package/hooks/blocking/_md_to_html_blocker_test_support.py +0 -65
  133. package/hooks/blocking/conftest.py +0 -30
  134. package/hooks/blocking/md_path_exemptions.py +0 -224
  135. package/hooks/blocking/md_to_html_blocker.py +0 -155
  136. package/hooks/blocking/test_md_to_html_blocker_exemptions.py +0 -434
  137. package/hooks/blocking/test_md_to_html_blocker_extensions.py +0 -157
  138. package/hooks/blocking/test_md_to_html_blocker_path_resolution.py +0 -336
  139. package/hooks/hooks_constants/doc_gist_auto_publish_constants.py +0 -18
  140. package/hooks/hooks_constants/html_companion_constants.py +0 -20
  141. package/hooks/hooks_constants/md_to_html_blocker_constants.py +0 -76
  142. package/hooks/hooks_constants/test_md_to_html_blocker_constants.py +0 -125
  143. package/hooks/workflow/doc_gist_auto_publish.py +0 -144
  144. package/hooks/workflow/md_to_html_companion.py +0 -358
  145. package/hooks/workflow/test_doc_gist_auto_publish.py +0 -117
  146. package/hooks/workflow/test_md_to_html_companion.py +0 -613
  147. package/skills/bugteam/reference/audit-contract.md +0 -163
  148. package/skills/bugteam/scripts/_bugteam_permissions_common.py +0 -455
  149. package/skills/bugteam/scripts/bugteam_scripts_constants/claude_permissions_common_constants.py +0 -69
  150. package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -280
  151. package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -266
  152. package/skills/bugteam/scripts/test__bugteam_permissions_common.py +0 -160
  153. package/skills/bugteam/scripts/test_agent_config_carveout.py +0 -356
  154. package/skills/bugteam/scripts/test_bugteam_permissions_common.py +0 -140
  155. package/skills/doc-gist/CLAUDE.md +0 -25
  156. package/skills/doc-gist/SKILL.md +0 -97
  157. package/skills/doc-gist/references/CLAUDE.md +0 -9
  158. package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +0 -453
  159. package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +0 -515
  160. package/skills/doc-gist/references/examples/03-code-review-pr.html +0 -638
  161. package/skills/doc-gist/references/examples/04-code-understanding.html +0 -491
  162. package/skills/doc-gist/references/examples/05-design-system.html +0 -629
  163. package/skills/doc-gist/references/examples/06-component-variants.html +0 -605
  164. package/skills/doc-gist/references/examples/07-prototype-animation.html +0 -455
  165. package/skills/doc-gist/references/examples/08-prototype-interaction.html +0 -396
  166. package/skills/doc-gist/references/examples/09-slide-deck.html +0 -592
  167. package/skills/doc-gist/references/examples/10-svg-illustrations.html +0 -492
  168. package/skills/doc-gist/references/examples/11-status-report.html +0 -528
  169. package/skills/doc-gist/references/examples/12-incident-report.html +0 -596
  170. package/skills/doc-gist/references/examples/13-flowchart-diagram.html +0 -395
  171. package/skills/doc-gist/references/examples/14-research-feature-explainer.html +0 -381
  172. package/skills/doc-gist/references/examples/15-research-concept-explainer.html +0 -368
  173. package/skills/doc-gist/references/examples/16-implementation-plan.html +0 -702
  174. package/skills/doc-gist/references/examples/17-pr-writeup.html +0 -595
  175. package/skills/doc-gist/references/examples/18-editor-triage-board.html +0 -573
  176. package/skills/doc-gist/references/examples/19-editor-feature-flags.html +0 -663
  177. package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +0 -722
  178. package/skills/doc-gist/references/examples/21-decision-signoff.html +0 -546
  179. package/skills/doc-gist/references/examples/CLAUDE.md +0 -25
  180. package/skills/doc-gist/references/examples/README.md +0 -5
  181. package/skills/doc-gist/scripts/CLAUDE.md +0 -27
  182. package/skills/doc-gist/scripts/doc_gist_scripts_constants/CLAUDE.md +0 -10
  183. package/skills/doc-gist/scripts/doc_gist_scripts_constants/gist_upload_constants.py +0 -16
  184. package/skills/doc-gist/scripts/gist_upload.py +0 -177
  185. package/skills/doc-gist/scripts/test_gist_upload.py +0 -51
  186. /package/skills/{doc-gist/scripts/doc_gist_scripts_constants → log-audit/scripts/log_audit_constants}/__init__.py +0 -0
@@ -1,492 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Background jobs — header illustrations</title>
7
- <style>
8
- :root {
9
- --ivory: #FAF9F5;
10
- --slate: #141413;
11
- --clay: #D97757;
12
- --oat: #E3DACC;
13
- --olive: #788C5D;
14
- --gray-150:#F0EEE6;
15
- --gray-300:#D1CFC5;
16
- --gray-500:#87867F;
17
- --gray-700:#3D3D3A;
18
-
19
- --serif: ui-serif, Georgia, "Times New Roman", serif;
20
- --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
21
- --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
22
- }
23
-
24
- * { margin: 0; padding: 0; box-sizing: border-box; }
25
-
26
- body {
27
- background: var(--ivory);
28
- color: var(--slate);
29
- font-family: var(--sans);
30
- -webkit-font-smoothing: antialiased;
31
- padding: 64px 24px 96px;
32
- }
33
-
34
- .sheet {
35
- max-width: 760px;
36
- margin: 0 auto;
37
- }
38
-
39
- header { margin-bottom: 56px; }
40
-
41
- h1 {
42
- font-family: var(--serif);
43
- font-weight: 500;
44
- font-size: 34px;
45
- letter-spacing: -0.01em;
46
- margin-bottom: 10px;
47
- }
48
-
49
- .lead {
50
- font-size: 14px;
51
- line-height: 1.6;
52
- color: var(--gray-700);
53
- max-width: 560px;
54
- }
55
-
56
- .meta {
57
- font-family: var(--mono);
58
- font-size: 11px;
59
- color: var(--gray-500);
60
- margin-top: 18px;
61
- }
62
-
63
- /* ---------------------------------------------------------------- */
64
-
65
- figure {
66
- margin: 0 0 72px 0;
67
- }
68
-
69
- .canvas {
70
- border: 1px solid var(--gray-300);
71
- border-radius: 12px;
72
- overflow: hidden;
73
- background: var(--ivory);
74
- }
75
-
76
- .canvas svg { display: block; width: 100%; height: auto; }
77
-
78
- figcaption {
79
- display: flex;
80
- align-items: baseline;
81
- justify-content: space-between;
82
- gap: 24px;
83
- padding: 18px 4px 0;
84
- }
85
-
86
- .cap-text { flex: 1; }
87
-
88
- .cap-title {
89
- font-family: var(--serif);
90
- font-size: 19px;
91
- font-weight: 500;
92
- margin-bottom: 4px;
93
- }
94
-
95
- .cap-sub {
96
- font-size: 13px;
97
- line-height: 1.55;
98
- color: var(--gray-500);
99
- }
100
-
101
- .dl {
102
- flex-shrink: 0;
103
- font-family: var(--mono);
104
- font-size: 11px;
105
- color: var(--slate);
106
- background: var(--gray-150);
107
- border: 1px solid var(--gray-300);
108
- border-radius: 6px;
109
- padding: 7px 12px;
110
- cursor: pointer;
111
- }
112
- .dl:hover { background: var(--oat); }
113
- .dl:active { transform: translateY(1px); }
114
-
115
- /* ----------------------------------------------------------------
116
- Palette reference strip
117
- ---------------------------------------------------------------- */
118
- .palette {
119
- border-top: 1px solid var(--gray-300);
120
- padding-top: 36px;
121
- margin-top: 8px;
122
- }
123
-
124
- .palette h2 {
125
- font-family: var(--serif);
126
- font-weight: 500;
127
- font-size: 19px;
128
- margin-bottom: 18px;
129
- }
130
-
131
- .swatches {
132
- display: grid;
133
- grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
134
- gap: 10px;
135
- margin-bottom: 32px;
136
- }
137
-
138
- .swatch {
139
- border: 1px solid var(--gray-300);
140
- border-radius: 8px;
141
- overflow: hidden;
142
- background: #fff;
143
- }
144
-
145
- .swatch-chip {
146
- height: 44px;
147
- }
148
-
149
- .swatch-meta {
150
- padding: 8px 10px 10px;
151
- }
152
-
153
- .swatch-name {
154
- font-size: 12px;
155
- color: var(--gray-700);
156
- }
157
-
158
- .swatch-hex {
159
- font-family: var(--mono);
160
- font-size: 10px;
161
- color: var(--gray-500);
162
- }
163
-
164
- .notes {
165
- font-size: 13px;
166
- line-height: 1.7;
167
- color: var(--gray-700);
168
- list-style: none;
169
- }
170
-
171
- .notes li {
172
- padding-left: 18px;
173
- position: relative;
174
- margin-bottom: 6px;
175
- }
176
-
177
- .notes li::before {
178
- content: "";
179
- position: absolute;
180
- left: 0;
181
- top: 0.65em;
182
- width: 8px;
183
- height: 1px;
184
- background: var(--gray-500);
185
- }
186
- </style>
187
- </head>
188
- <body>
189
- <div class="sheet">
190
-
191
- <header>
192
- <h1>Background jobs — header illustrations</h1>
193
- <p class="lead">
194
- Three 720×320 hand-drawn SVGs for the Birchline docs section on
195
- background jobs. Flat fills, 1.5–2px strokes, palette-locked. Each
196
- exports standalone via the button below it.
197
- </p>
198
- <div class="meta">720 × 320 · inline SVG · no external assets</div>
199
- </header>
200
-
201
- <!-- ============================================================
202
- A — Queue
203
- ============================================================ -->
204
- <figure>
205
- <div class="canvas">
206
- <svg id="ill-queue" xmlns="http://www.w3.org/2000/svg" width="720" height="320" viewBox="0 0 720 320">
207
- <defs>
208
- <style>
209
- .m { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 11px; }
210
- .s { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-size: 12px; }
211
- </style>
212
- <marker id="qa" markerWidth="10" markerHeight="10" refX="8" refY="4" orient="auto" markerUnits="userSpaceOnUse">
213
- <path d="M0,0 L0,8 L8,4 z" fill="#87867F"/>
214
- </marker>
215
- </defs>
216
-
217
- <rect width="720" height="320" fill="#FAF9F5"/>
218
-
219
- <!-- queue label -->
220
- <text x="60" y="96" class="s" fill="#87867F">queue</text>
221
-
222
- <!-- five job rects -->
223
- <g>
224
- <rect x="60" y="110" width="70" height="100" rx="10" fill="#F0EEE6" stroke="#3D3D3A" stroke-width="1.5"/>
225
- <text x="95" y="164" text-anchor="middle" class="m" fill="#3D3D3A">job 5</text>
226
-
227
- <rect x="140" y="110" width="70" height="100" rx="10" fill="#F0EEE6" stroke="#3D3D3A" stroke-width="1.5"/>
228
- <text x="175" y="164" text-anchor="middle" class="m" fill="#3D3D3A">job 4</text>
229
-
230
- <rect x="220" y="110" width="70" height="100" rx="10" fill="#F0EEE6" stroke="#3D3D3A" stroke-width="1.5"/>
231
- <text x="255" y="164" text-anchor="middle" class="m" fill="#3D3D3A">job 3</text>
232
-
233
- <rect x="300" y="110" width="70" height="100" rx="10" fill="#F0EEE6" stroke="#3D3D3A" stroke-width="1.5"/>
234
- <text x="335" y="164" text-anchor="middle" class="m" fill="#3D3D3A">job 2</text>
235
-
236
- <!-- head of queue, highlighted -->
237
- <rect x="380" y="110" width="70" height="100" rx="10" fill="#D97757" stroke="#141413" stroke-width="2"/>
238
- <text x="415" y="164" text-anchor="middle" class="m" fill="#FAF9F5">job 1</text>
239
- </g>
240
-
241
- <!-- arrow to worker -->
242
- <line x1="458" y1="160" x2="522" y2="160" stroke="#87867F" stroke-width="1.5" marker-end="url(#qa)"/>
243
-
244
- <!-- worker -->
245
- <rect x="530" y="90" width="130" height="140" rx="10" fill="#E3DACC" stroke="#141413" stroke-width="2"/>
246
- <text x="595" y="156" text-anchor="middle" class="m" fill="#141413">worker</text>
247
- <text x="595" y="172" text-anchor="middle" class="m" fill="#87867F">pool=4</text>
248
-
249
- <!-- annotations -->
250
- <text x="415" y="234" text-anchor="middle" class="s" fill="#87867F">next to run</text>
251
- <text x="60" y="258" class="s" fill="#87867F">Jobs are pulled FIFO; the worker leases one at a time.</text>
252
- </svg>
253
- </div>
254
- <figcaption>
255
- <div class="cap-text">
256
- <div class="cap-title">Queue</div>
257
- <div class="cap-sub">For "How jobs are picked up" — intro page header.</div>
258
- </div>
259
- <button class="dl" data-target="ill-queue" data-filename="birchline-jobs-queue.svg">Download SVG</button>
260
- </figcaption>
261
- </figure>
262
-
263
- <!-- ============================================================
264
- B — Retry with backoff
265
- ============================================================ -->
266
- <figure>
267
- <div class="canvas">
268
- <svg id="ill-retry" xmlns="http://www.w3.org/2000/svg" width="720" height="320" viewBox="0 0 720 320">
269
- <defs>
270
- <style>
271
- .m { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 11px; }
272
- .s { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-size: 12px; }
273
- </style>
274
- </defs>
275
-
276
- <rect width="720" height="320" fill="#FAF9F5"/>
277
-
278
- <!-- timeline axis -->
279
- <line x1="60" y1="190" x2="660" y2="190" stroke="#D1CFC5" stroke-width="1.5"/>
280
- <text x="60" y="214" class="s" fill="#87867F">t = 0</text>
281
- <text x="660" y="214" text-anchor="end" class="s" fill="#87867F">time →</text>
282
-
283
- <!-- attempts: exponential spacing at x = 100, 170, 310, 590 -->
284
- <!-- attempt 1 (fail) -->
285
- <circle cx="100" cy="190" r="8" fill="#FAF9F5" stroke="#D97757" stroke-width="2"/>
286
- <line x1="96" y1="186" x2="104" y2="194" stroke="#D97757" stroke-width="1.5"/>
287
- <line x1="104" y1="186" x2="96" y2="194" stroke="#D97757" stroke-width="1.5"/>
288
- <text x="100" y="222" text-anchor="middle" class="m" fill="#3D3D3A">try 1</text>
289
-
290
- <!-- attempt 2 (fail) -->
291
- <circle cx="170" cy="190" r="8" fill="#FAF9F5" stroke="#D97757" stroke-width="2"/>
292
- <line x1="166" y1="186" x2="174" y2="194" stroke="#D97757" stroke-width="1.5"/>
293
- <line x1="174" y1="186" x2="166" y2="194" stroke="#D97757" stroke-width="1.5"/>
294
- <text x="170" y="222" text-anchor="middle" class="m" fill="#3D3D3A">try 2</text>
295
-
296
- <!-- attempt 3 (fail) -->
297
- <circle cx="310" cy="190" r="8" fill="#FAF9F5" stroke="#D97757" stroke-width="2"/>
298
- <line x1="306" y1="186" x2="314" y2="194" stroke="#D97757" stroke-width="1.5"/>
299
- <line x1="314" y1="186" x2="306" y2="194" stroke="#D97757" stroke-width="1.5"/>
300
- <text x="310" y="222" text-anchor="middle" class="m" fill="#3D3D3A">try 3</text>
301
-
302
- <!-- attempt 4 (success) -->
303
- <circle cx="590" cy="190" r="9" fill="#788C5D" stroke="#141413" stroke-width="1.5"/>
304
- <path d="M585,190 L589,194 L596,185" fill="none" stroke="#FAF9F5" stroke-width="1.5" stroke-linecap="round"/>
305
- <text x="590" y="222" text-anchor="middle" class="m" fill="#3D3D3A">try 4</text>
306
-
307
- <!-- dashed backoff arcs (loop back over the gap) -->
308
- <path d="M 100 182 Q 135 130 170 182" fill="none" stroke="#87867F" stroke-width="1.5" stroke-dasharray="4 4"/>
309
- <text x="135" y="124" text-anchor="middle" class="m" fill="#87867F">+1s</text>
310
-
311
- <path d="M 170 182 Q 240 110 310 182" fill="none" stroke="#87867F" stroke-width="1.5" stroke-dasharray="4 4"/>
312
- <text x="240" y="104" text-anchor="middle" class="m" fill="#87867F">+2s</text>
313
-
314
- <path d="M 310 182 Q 450 80 590 182" fill="none" stroke="#87867F" stroke-width="1.5" stroke-dasharray="4 4"/>
315
- <text x="450" y="74" text-anchor="middle" class="m" fill="#87867F">+4s</text>
316
-
317
- <!-- annotation -->
318
- <text x="60" y="262" class="s" fill="#87867F">Each failure waits twice as long before re-queuing; jitter not pictured.</text>
319
- </svg>
320
- </div>
321
- <figcaption>
322
- <div class="cap-text">
323
- <div class="cap-title">Retry with backoff</div>
324
- <div class="cap-sub">For "Handling failures" — retry policy header.</div>
325
- </div>
326
- <button class="dl" data-target="ill-retry" data-filename="birchline-jobs-retry.svg">Download SVG</button>
327
- </figcaption>
328
- </figure>
329
-
330
- <!-- ============================================================
331
- C — Fan-out
332
- ============================================================ -->
333
- <figure>
334
- <div class="canvas">
335
- <svg id="ill-fanout" xmlns="http://www.w3.org/2000/svg" width="720" height="320" viewBox="0 0 720 320">
336
- <defs>
337
- <style>
338
- .m { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 11px; }
339
- .s { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-size: 12px; }
340
- </style>
341
- <marker id="fa" markerWidth="9" markerHeight="9" refX="7" refY="3.5" orient="auto" markerUnits="userSpaceOnUse">
342
- <path d="M0,0 L0,7 L7,3.5 z" fill="#87867F"/>
343
- </marker>
344
- </defs>
345
-
346
- <rect width="720" height="320" fill="#FAF9F5"/>
347
-
348
- <!-- source -->
349
- <rect x="60" y="128" width="110" height="64" rx="10" fill="#E3DACC" stroke="#141413" stroke-width="2"/>
350
- <text x="115" y="158" text-anchor="middle" class="m" fill="#141413">enqueue</text>
351
- <text x="115" y="172" text-anchor="middle" class="m" fill="#87867F">batch()</text>
352
-
353
- <!-- fan-out arrows: from (170,160) to four shard boxes at x=300 -->
354
- <line x1="170" y1="160" x2="296" y2="64" stroke="#87867F" stroke-width="1.5" marker-end="url(#fa)"/>
355
- <line x1="170" y1="160" x2="296" y2="128" stroke="#87867F" stroke-width="1.5" marker-end="url(#fa)"/>
356
- <line x1="170" y1="160" x2="296" y2="192" stroke="#87867F" stroke-width="1.5" marker-end="url(#fa)"/>
357
- <line x1="170" y1="160" x2="296" y2="256" stroke="#87867F" stroke-width="1.5" marker-end="url(#fa)"/>
358
-
359
- <!-- four shard boxes -->
360
- <g>
361
- <rect x="300" y="44" width="120" height="40" rx="10" fill="#F0EEE6" stroke="#3D3D3A" stroke-width="1.5"/>
362
- <text x="360" y="69" text-anchor="middle" class="m" fill="#3D3D3A">shard 0</text>
363
-
364
- <rect x="300" y="108" width="120" height="40" rx="10" fill="#F0EEE6" stroke="#3D3D3A" stroke-width="1.5"/>
365
- <text x="360" y="133" text-anchor="middle" class="m" fill="#3D3D3A">shard 1</text>
366
-
367
- <rect x="300" y="172" width="120" height="40" rx="10" fill="#F0EEE6" stroke="#3D3D3A" stroke-width="1.5"/>
368
- <text x="360" y="197" text-anchor="middle" class="m" fill="#3D3D3A">shard 2</text>
369
-
370
- <rect x="300" y="236" width="120" height="40" rx="10" fill="#F0EEE6" stroke="#3D3D3A" stroke-width="1.5"/>
371
- <text x="360" y="261" text-anchor="middle" class="m" fill="#3D3D3A">shard 3</text>
372
- </g>
373
-
374
- <!-- converge arrows to merge -->
375
- <line x1="420" y1="64" x2="546" y2="160" stroke="#87867F" stroke-width="1.5" marker-end="url(#fa)"/>
376
- <line x1="420" y1="128" x2="546" y2="160" stroke="#87867F" stroke-width="1.5" marker-end="url(#fa)"/>
377
- <line x1="420" y1="192" x2="546" y2="160" stroke="#87867F" stroke-width="1.5" marker-end="url(#fa)"/>
378
- <line x1="420" y1="256" x2="546" y2="160" stroke="#87867F" stroke-width="1.5" marker-end="url(#fa)"/>
379
-
380
- <!-- merge box -->
381
- <rect x="550" y="128" width="110" height="64" rx="10" fill="#788C5D" stroke="#141413" stroke-width="2"/>
382
- <text x="605" y="158" text-anchor="middle" class="m" fill="#FAF9F5">merge</text>
383
- <text x="605" y="172" text-anchor="middle" class="m" fill="#E3DACC">await all</text>
384
-
385
- <!-- annotations -->
386
- <text x="232" y="42" class="s" fill="#87867F">fan-out</text>
387
- <text x="486" y="42" text-anchor="end" class="s" fill="#87867F">fan-in</text>
388
- <text x="60" y="300" class="s" fill="#87867F">Parent job spawns N children, then blocks on a completion barrier.</text>
389
- </svg>
390
- </div>
391
- <figcaption>
392
- <div class="cap-text">
393
- <div class="cap-title">Fan-out / fan-in</div>
394
- <div class="cap-sub">For "Batch and parallel work" — fan-out pattern header.</div>
395
- </div>
396
- <button class="dl" data-target="ill-fanout" data-filename="birchline-jobs-fanout.svg">Download SVG</button>
397
- </figcaption>
398
- </figure>
399
-
400
- <!-- ============================================================
401
- Palette + usage notes
402
- ============================================================ -->
403
- <section class="palette">
404
- <h2>Palette &amp; rules</h2>
405
-
406
- <div class="swatches">
407
- <div class="swatch">
408
- <div class="swatch-chip" style="background:#FAF9F5"></div>
409
- <div class="swatch-meta">
410
- <div class="swatch-name">ivory</div>
411
- <div class="swatch-hex">#FAF9F5</div>
412
- </div>
413
- </div>
414
- <div class="swatch">
415
- <div class="swatch-chip" style="background:#141413"></div>
416
- <div class="swatch-meta">
417
- <div class="swatch-name">slate</div>
418
- <div class="swatch-hex">#141413</div>
419
- </div>
420
- </div>
421
- <div class="swatch">
422
- <div class="swatch-chip" style="background:#D97757"></div>
423
- <div class="swatch-meta">
424
- <div class="swatch-name">clay</div>
425
- <div class="swatch-hex">#D97757</div>
426
- </div>
427
- </div>
428
- <div class="swatch">
429
- <div class="swatch-chip" style="background:#788C5D"></div>
430
- <div class="swatch-meta">
431
- <div class="swatch-name">olive</div>
432
- <div class="swatch-hex">#788C5D</div>
433
- </div>
434
- </div>
435
- <div class="swatch">
436
- <div class="swatch-chip" style="background:#E3DACC"></div>
437
- <div class="swatch-meta">
438
- <div class="swatch-name">oat</div>
439
- <div class="swatch-hex">#E3DACC</div>
440
- </div>
441
- </div>
442
- <div class="swatch">
443
- <div class="swatch-chip" style="background:#F0EEE6"></div>
444
- <div class="swatch-meta">
445
- <div class="swatch-name">gray-150</div>
446
- <div class="swatch-hex">#F0EEE6</div>
447
- </div>
448
- </div>
449
- <div class="swatch">
450
- <div class="swatch-chip" style="background:#D1CFC5"></div>
451
- <div class="swatch-meta">
452
- <div class="swatch-name">gray-300</div>
453
- <div class="swatch-hex">#D1CFC5</div>
454
- </div>
455
- </div>
456
- <div class="swatch">
457
- <div class="swatch-chip" style="background:#87867F"></div>
458
- <div class="swatch-meta">
459
- <div class="swatch-name">gray-500</div>
460
- <div class="swatch-hex">#87867F</div>
461
- </div>
462
- </div>
463
- </div>
464
-
465
- <ul class="notes">
466
- <li>Strokes are 1.5px for neutral boxes, 2px for emphasised containers.</li>
467
- <li>All rectangles use <code>rx="10"</code>; no drop shadows or gradients.</li>
468
- <li>Labels inside boxes are 11px mono; annotations outside are 12px sans, gray-500.</li>
469
- <li>Clay marks "the thing in focus"; olive marks "success / done".</li>
470
- <li>Each SVG carries its own <code>&lt;style&gt;</code> block so the download stands alone.</li>
471
- </ul>
472
- </section>
473
-
474
- </div>
475
-
476
- <script>
477
- document.querySelectorAll('.dl').forEach(function (btn) {
478
- btn.addEventListener('click', function () {
479
- var svg = document.getElementById(btn.dataset.target);
480
- var src = new XMLSerializer().serializeToString(svg);
481
- var blob = new Blob([src], { type: 'image/svg+xml;charset=utf-8' });
482
- var url = URL.createObjectURL(blob);
483
- var a = document.createElement('a');
484
- a.href = url;
485
- a.download = btn.dataset.filename || 'illustration.svg';
486
- a.click();
487
- setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
488
- });
489
- });
490
- </script>
491
- </body>
492
- </html>