@bompus/house-rules 0.11.0 → 0.13.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 (111) hide show
  1. package/CODE_OF_CONDUCT.md +83 -0
  2. package/README.md +91 -60
  3. package/compose.mjs +8 -2
  4. package/composition.mjs +11 -3
  5. package/config-view.mjs +18 -3
  6. package/config.mjs +74 -13
  7. package/docs/assets/overview.png +0 -0
  8. package/docs/configuration.md +85 -9
  9. package/package.json +4 -2
  10. package/rules/core.md +118 -209
  11. package/rules/modifiers/backlog-outline.md +25 -0
  12. package/rules/modifiers/backlog-visual.md +16 -0
  13. package/rules/modifiers/coded-offers.md +47 -17
  14. package/rules/modifiers/cross-session-relay.md +23 -0
  15. package/rules/modifiers/low-quota-handoff.md +4 -3
  16. package/rules/modifiers/model-default-questions.md +33 -0
  17. package/rules/modifiers/multi-agent.md +6 -2
  18. package/rules/modifiers/no-attribution.md +7 -1
  19. package/rules/modifiers/periodic-updates.md +25 -0
  20. package/rules/modifiers/plan-files.md +35 -3
  21. package/rules/modifiers/release-batching.md +4 -2
  22. package/rules/modifiers/shared-host-load.md +13 -42
  23. package/rules/modifiers/squash-landing.md +1 -1
  24. package/rules/modifiers/upstream-contributions.md +45 -0
  25. package/rules/modifiers/web-image-formats.md +35 -0
  26. package/rules/references/backlog-view.md +154 -0
  27. package/rules/references/landing.md +14 -14
  28. package/rules/references/multi-agent.md +6 -2
  29. package/rules/references/release-batching.md +27 -4
  30. package/rules/references/squash-landing.md +10 -4
  31. package/rules/references/thread-visuals.md +45 -0
  32. package/setup.mjs +87 -17
  33. package/skills/hr-agent-guidance-audit/SKILL.md +10 -5
  34. package/skills/hr-agent-guidance-audit/references/prune-workflow.md +72 -0
  35. package/skills/hr-agent-guidance-audit/references/records-and-lessons.md +1 -1
  36. package/skills/hr-agent-guidance-audit/references/retirement-verdicts.md +49 -0
  37. package/skills/hr-agent-guidance-refresh/SKILL.md +25 -57
  38. package/skills/hr-agent-guidance-refresh/references/verification.md +1 -1
  39. package/skills/hr-audit-choices/SKILL.md +1 -1
  40. package/skills/hr-benchmarking/SKILL.md +122 -159
  41. package/skills/hr-benchmarking/references/javascript.md +113 -0
  42. package/skills/hr-benchmarking/references/tools.md +62 -57
  43. package/skills/hr-better-accessibility/SKILL.md +1 -1
  44. package/skills/hr-better-accessibility/screen-readers.md +1 -0
  45. package/skills/hr-code-review/SKILL.md +19 -3
  46. package/skills/hr-code-review/agents/openai.yaml +1 -1
  47. package/skills/hr-code-review/references/acp-client.md +43 -0
  48. package/skills/{hr-change-impact/SKILL.md → hr-code-review/references/impact.md} +2 -12
  49. package/skills/hr-code-review/references/panel-adjudication.md +58 -0
  50. package/skills/hr-code-review/references/panel-plan.md +61 -0
  51. package/skills/hr-code-review/references/panel-recommendations.json +105 -0
  52. package/skills/hr-code-review/references/panel-recommendations.md +46 -0
  53. package/skills/hr-code-review/references/panel-setup.md +54 -0
  54. package/skills/hr-code-review/references/reviewer-role.md +31 -0
  55. package/skills/hr-code-review/scripts/acp-panel-client.mjs +299 -0
  56. package/skills/hr-code-review/scripts/check-receipts.mjs +263 -0
  57. package/skills/hr-code-review/scripts/panel-plan.mjs +69 -0
  58. package/skills/hr-code-review/scripts/panel-preferences.mjs +220 -0
  59. package/skills/hr-design-exploration/SKILL.md +24 -1
  60. package/skills/hr-design-exploration/agents/openai.yaml +2 -2
  61. package/skills/hr-diagnosing-bugs/SKILL.md +2 -2
  62. package/skills/hr-diagnosing-bugs/references/reporting.md +29 -4
  63. package/skills/hr-diagnosing-bugs/scripts/check-pr-offer.mjs +47 -0
  64. package/skills/hr-explain-code/SKILL.md +1 -1
  65. package/skills/hr-extract-shared-steps/SKILL.md +1 -1
  66. package/skills/hr-forgotten-work-audit/SKILL.md +130 -0
  67. package/skills/hr-forgotten-work-audit/references/brief-template.md +56 -0
  68. package/skills/hr-forgotten-work-audit/references/result-format.md +46 -0
  69. package/skills/hr-handoff/LICENSE +21 -0
  70. package/skills/hr-handoff/NOTICE.md +29 -0
  71. package/skills/hr-handoff/SKILL.md +24 -1
  72. package/skills/hr-handoff/references/reconciliation.md +25 -6
  73. package/skills/hr-handoff/references/successor-thread.md +76 -0
  74. package/skills/hr-handoff/scripts/check-reconciliation.mjs +48 -6
  75. package/skills/hr-house-rules-setup/SKILL.md +22 -8
  76. package/skills/hr-lean-plan/SKILL.md +4 -0
  77. package/skills/hr-maintainability-review/SKILL.md +14 -4
  78. package/skills/hr-maintainability-review/agents/openai.yaml +1 -1
  79. package/skills/hr-manual-qa/SKILL.md +1 -1
  80. package/skills/hr-ordering-tests/SKILL.md +1 -1
  81. package/skills/hr-plain-prose/SKILL.md +7 -4
  82. package/skills/hr-pr-followup/SKILL.md +6 -3
  83. package/skills/hr-pr-followup/references/review-helpers.md +21 -0
  84. package/skills/hr-pr-followup/scripts/check-landing.py +204 -0
  85. package/skills/hr-pr-followup/scripts/merge-pr.sh +100 -0
  86. package/skills/hr-pr-followup/scripts/verify-landed.sh +184 -0
  87. package/skills/hr-read-reddit/SKILL.md +1 -1
  88. package/skills/hr-research-shared-links/SKILL.md +103 -0
  89. package/skills/hr-sqlite/SKILL.md +174 -0
  90. package/skills/hr-sqlite/agents/openai.yaml +2 -0
  91. package/skills/hr-sqlite/references/evidence.md +94 -0
  92. package/skills/hr-sqlite/references/tool-decisions.md +39 -0
  93. package/skills/hr-sqlite/scripts/inspect-sqlite.py +245 -0
  94. package/skills/hr-stock-ui-audit/SKILL.md +1 -1
  95. package/skills/hr-test-audit/LICENSE +21 -0
  96. package/skills/hr-test-audit/NOTICE.md +67 -0
  97. package/skills/hr-usage-report/SKILL.md +90 -0
  98. package/skills/hr-usage-report/agents/openai.yaml +2 -0
  99. package/skills/hr-usage-report/assets/example-report.json +125 -0
  100. package/skills/hr-usage-report/assets/report-template.html +377 -0
  101. package/skills/hr-usage-report/scripts/render-report.ts +86 -0
  102. package/skills/hr-usage-report/scripts/usage-by-model.ts +499 -0
  103. package/skills/hr-what-next/SKILL.md +100 -10
  104. package/skills/hr-what-next/references/reporting.md +13 -22
  105. package/skills/hr-what-next/scripts/check-open-work.mjs +711 -0
  106. package/skills/hr-writing-pr/SKILL.md +29 -14
  107. package/skills/hr-writing-pr/scripts/benefit-chart.py +200 -0
  108. package/docs/npm-release.md +0 -45
  109. package/rules/modifiers/swarmail.md +0 -12
  110. package/skills/hr-benchmarking/references/priority-findings-20261006.md +0 -115
  111. package/skills/hr-change-impact/agents/openai.yaml +0 -5
@@ -42,21 +42,27 @@ Resolve mismatches between the description and the implementation before calling
42
42
 
43
43
  ## Title and body
44
44
 
45
- Write a title naming the resulting behavior or fixed failure. Use the repository's title convention when it has one. Check the title's type and scope against the diff's dominant change. A `docs:` title on a diff that adds an executable installer misfiles the squash commit. When no PR template exists, the title convention is the only template; default to Conventional Commits `type(scope):` unless the repository's recent history uses another style. Flag a mixed diff as a possible split into separate PRs (the `hr-split-to-prs` skill, where installed) instead of stretching the title to cover it.
45
+ Write a title naming the resulting behavior or fixed failure, in the words of the person who feels it ("fork threads open faster"), not the mechanism ("skip hidden ancestor payloads"). Use the repository's title convention when it has one. When the PR title becomes the squash commit line, keep a measured speedup out of it, because the figure goes stale there. A repository whose convention asks for the figure keeps it. Put the qualified result, with the workload it holds for, in the body's opening sentence.
46
46
 
47
- Lead the body with the concrete problem and resulting behavior. A small change may need only a paragraph and a validation sentence. Expand only where the reviewer needs more context:
47
+ Check the title's type and scope against the diff's dominant change. A `docs:` title on a diff that adds an executable installer misfiles the squash commit. When no PR template exists, the title convention is the only template; default to Conventional Commits `type(scope):` unless the repository's recent history uses another style. Flag a mixed diff as a possible split into separate PRs (the `hr-split-to-prs` skill, where installed) instead of stretching the title to cover it.
48
+
49
+ Open the body with one sentence that states the benefit, before any problem detail. For a measured change it carries the qualified figure and its workload ("Clean Android builds finish 32% faster, 67.7 s to 46.2 s on a warm Gradle cache"). For a bug fix it says who hit the bug and what now works ("Cursor title generation no longer leaks a SQLite file handle on every call"). The problem and resulting behavior follow. A small change may need only a paragraph and a validation sentence. Expand only where the reviewer needs more context:
48
50
 
49
51
  - **Bug fix:** trigger, previous behavior, corrected behavior, and regression proof.
50
52
  - **Feature:** observable capability, a small usage example, and supported limits.
51
53
  - **Refactor:** motivation, the structural change, and evidence that required behavior is preserved.
52
54
 
53
- Explain implementation details only when they clarify a decision or help assess correctness. Include compatibility, dependency, migration, or documentation implications when the diff creates them. When the change has a hard-to-reverse surface (host-level effects such as `sudo install-deps`, migrations, destructive actions), say so in one sentence; never a fixed risk section, and nothing on purely additive changes. Identify a useful review starting point for a complex change, using `path:line` anchors for load-bearing claims.
55
+ Explain implementation details only when they clarify a decision or help assess correctness. Include compatibility, dependency, migration, or documentation implications when the diff creates them. When the change has a hard-to-reverse surface (host-level effects such as `sudo install-deps`, migrations, destructive actions), say so in one sentence; never a fixed risk section, and nothing on purely additive changes.
56
+
57
+ For a change too large to read in the diff's file order, give a reading order. Use a short numbered list where each step says what it accomplishes ("the contract, then the service that implements it, then its callers"), and anchor load-bearing claims with `path:line`. Put mechanical files in a last step that says what you checked and the pattern that holds ("same rename in all nine drivers"). Add a "Decisions for you" list only when the reviewer has a call that tests cannot make: a tradeoff, a compatibility promise, a product or scope choice, or an accepted risk. Leave bugs, missing tests and nits out of it, and omit the list when there is no such call. Name adjacent work you left out on purpose in a "Not covered" line.
58
+
59
+ In a stack, open with the parent ("Stacked on #123.") and describe only this layer, measured from its parent; that layer is its final combined change. When the body attributes behavior to another layer or describes a dependency on it, name that layer by number ("added in #123", "wired into the UI in #125"). Do not describe or judge its code.
54
60
 
55
- Describe the final combined change. Leave out intermediate attempts, commit reshuffling, conversational history, and file inventories already visible in the diff. Write for the reviewer in plain language: no unexplained jargon, and no narrative about how the change was produced. Review panels, models consulted, harnesses, and agent process never appear in titles, bodies, or PR comments; that detail lives in plan files and session records. For routine clarifications, update the title and body. Material scope changes follow the replacement rule above.
61
+ Describe the final combined change. Leave out intermediate attempts, commit reshuffling, conversational history, and file inventories already visible in the diff. Write for the reviewer in plain language: no unexplained jargon, and no narrative about how the change was produced. Review panels, models consulted, harnesses, and agent process never appear in titles, bodies, or PR comments, except for a disclosure the repository's contribution guidelines or PR template ask for, which is given as asked and no further; that detail otherwise lives in plan files and session records. For routine clarifications, update the title and body. Material scope changes follow the replacement rule above.
56
62
 
57
63
  ## Evidence that earns its space
58
64
 
59
- Report relevant checks and their actual outcomes, including material failures and unverified behavior. Name the tests or commands run and their scope; a suite-wide pass count alone is not evidence for the changed behavior. When generated files dominate the diff, give the authored line count alongside the headline number so the size does not mislead review. Distinguish newly introduced failures from established baseline failures only when a comparison supports that claim. Keep detailed logs in a linked artifact when the short result is sufficient.
65
+ Report relevant checks and their actual outcomes, including material failures and unverified behavior. Name the tests or commands run and their scope, and the head commit they ran against; a suite-wide pass count alone is not evidence for the changed behavior. When generated files dominate the diff, give the authored line count alongside the headline number so the size does not mislead review. Distinguish newly introduced failures from established baseline failures only when a comparison supports that claim. Keep detailed logs in a linked artifact when the short result is sufficient.
60
66
 
61
67
  Use a small code example when it makes behavior concrete. For visual changes, use comparable before/after images when available. When the change replaces an existing procedure, state the prior and new procedure in one line each. For measured performance claims, follow the installed `hr-benchmarking` skill's
62
68
  "Report and decide" guidance for benefit columns, variability and claim limits.
@@ -85,20 +91,29 @@ outcomes visible; collapse long commands or supporting detail when useful.
85
91
  Required scope or approval sections stay, with only the justification and links
86
92
  the reviewer needs.
87
93
 
88
- For qualified measured performance changes outside the declared no-clear-change
89
- band, prefer a compact chart alongside the exact result table when it makes
90
- comparisons easier to scan. Skip charts
91
- that add no information, such as a single small change. Preview a proposed
92
- visual with the user before publishing a new visual style. Use labeled units,
93
- zero-based bar axes, readable contrast and meaningful precision. Show the
94
- workload and material limits beside it; a synthetic benchmark is not a
95
- production or UI speedup. Keep the table or equivalent text accessible, and
94
+ A qualified measured change outside the declared variation criterion, with
95
+ identical outputs, gets a
96
+ headline chart directly under the opening sentence, beside the exact result
97
+ table. Render it with `scripts/benefit-chart.py` in this skill's directory. It reads
98
+ a JSON spec and writes a dark PNG with labeled units, zero-based bars and a
99
+ benefit badge per row. Skip the chart only when every row is no clear change,
100
+ or the one row moved by less than 10%. Set the spec's top-level `band`
101
+ (required) to the declared variation criterion as a fraction of the baseline,
102
+ and name it beside the chart. If the criterion cannot be a fraction of the
103
+ baseline, skip the chart and label the result inconclusive.
104
+
105
+ Show the workload and material limits beside it; a synthetic benchmark is not a
106
+ production or UI speedup. Preview a chart in a different style with the user
107
+ before publishing it. The image is never the only place a value or caveat
108
+ appears. The opening sentence and the result table carry every figure, and `--table`
109
+ prints that table from the chart's spec. The alt text the script prints carries
110
+ them too. An agent or screen reader that cannot read the image loses nothing. Keep the table or equivalent text accessible, and
96
111
  attach PR-only graphics without committing them to the product repository.
97
112
 
98
113
  Scale structure to the change. Omit empty optional sections, placeholder text, guessed risk scores or review times, and coverage percentages that were not measured. Complete a required checklist with this PR's specifics rather than omitting it, and mark non-applicable items N/A with a reason. Preserve required template sections and mark unavailable evidence honestly.
99
114
 
100
115
  ## Completion check
101
116
 
102
- Every factual claim must be supported by inspected code, the originating request, or observed results. The opening explains what changes and why; the remaining text helps review it. Deliver the title and body in the form requested. Apply them to a remote PR only within the user's authorized scope. When the user's rules turn attribution off, include no `Made with` or other host attribution. After `gh pr create` or `gh pr edit`, reread the published body and strip any footer a harness appended.
117
+ Every factual claim must be supported by inspected code, the originating request, or observed results. The opening explains what changes and why; the remaining text helps review it. Deliver the title and body in the form requested. Apply them to a remote PR only within the user's authorized scope. When the user's rules turn attribution off, include no `Made with` or other host attribution beyond a disclosure the repository asks for. After `gh pr create` or `gh pr edit`, reread the published body and strip any footer a harness appended.
103
118
 
104
119
  Relevant validation stays in the description; extensive templates and review automation are outside this skill.
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env python3
2
+ """Render a before/after benefit chart as a PNG for a pull request, issue or discussion.
3
+
4
+ Usage: benefit-chart.py <spec.json> <out.png> [--table]
5
+
6
+ The spec holds a headline, a workload line and one row per measured metric:
7
+
8
+ {
9
+ "headline": "Sidebar search: typing one letter takes 319 ms, was 1,136 ms",
10
+ "workload": "1,300 threads, 1,057 matches, dev build; median of 3 runs",
11
+ "arms": ["Before", "After"],
12
+ "band": 0.03,
13
+ "note": "Lower is better.",
14
+ "rows": [
15
+ {"label": "Type one letter", "before": 1136, "after": 319, "unit": "ms"},
16
+ {"label": "Renders", "before": 36950, "after": 7693, "unit": "",
17
+ "words": ["fewer", "more"]}
18
+ ]
19
+ }
20
+
21
+ Row fields: label, before, after, unit (text after the value), lower_is_better
22
+ (default true), words (the two words after the percentage, for a good and a bad
23
+ change; default "lower"/"higher", or "higher"/"lower" when lower_is_better is false), and
24
+ note (extra text under the label). band is required: the variation criterion
25
+ declared before the first run, as a fraction of the baseline. A change at or
26
+ inside it is labeled "no clear change". Bars start at zero and share a scale per row.
27
+
28
+ Values must be non-negative. Prints the alt text for the image on stdout. With --table it
29
+ also prints a Markdown table of the same values, the text version of the chart
30
+ for readers and agents that cannot parse the image. Requires matplotlib.
31
+ """
32
+ import json
33
+ import math
34
+ import sys
35
+ import textwrap
36
+
37
+ try:
38
+ import matplotlib
39
+
40
+ matplotlib.use("Agg")
41
+ import matplotlib.pyplot as plt
42
+ from matplotlib.patches import FancyBboxPatch
43
+ except ImportError:
44
+ sys.exit("benefit-chart.py needs matplotlib (pip install matplotlib).")
45
+
46
+ BACKGROUND = "#0d1117"
47
+ TEXT = "#e6edf3"
48
+ MUTED = "#9da7b3"
49
+ BEFORE = "#6e7681"
50
+ GOOD = "#3fb950"
51
+ BAD = "#f85149"
52
+ NEUTRAL = "#8b949e"
53
+
54
+
55
+ def fmt(value):
56
+ magnitude = abs(value)
57
+ if float(value).is_integer():
58
+ return f"{value:,.0f}"
59
+ if magnitude >= 100:
60
+ return f"{value:,.0f}"
61
+ if magnitude >= 10:
62
+ return f"{value:,.1f}"
63
+ if magnitude >= 1:
64
+ return f"{value:,.2f}"
65
+ return f"{value:,.3f}"
66
+
67
+
68
+ def band_of(spec):
69
+ if "band" not in spec:
70
+ sys.exit('spec needs a top-level "band": the declared variation criterion as a fraction '
71
+ "of the baseline, such as 0.04.")
72
+ try:
73
+ if isinstance(spec["band"], bool):
74
+ raise TypeError
75
+ band = float(spec["band"])
76
+ except (TypeError, ValueError):
77
+ band = float("nan")
78
+ if not math.isfinite(band) or band < 0:
79
+ sys.exit('spec "band" must be a finite non-negative number.')
80
+ return band
81
+
82
+
83
+ def judge(row, band):
84
+ before, after = float(row["before"]), float(row["after"])
85
+ lower_is_better = row.get("lower_is_better", True)
86
+ if before == 0:
87
+ return NEUTRAL, "no baseline to compare", "no baseline to compare"
88
+ change = (after - before) / before
89
+ if abs(change) <= band:
90
+ return NEUTRAL, "no clear change", "no clear change"
91
+ improved = change < 0 if lower_is_better else change > 0
92
+ default_words = ("lower", "higher") if lower_is_better else ("higher", "lower")
93
+ words = row.get("words") or default_words
94
+ word = words[0] if improved else words[1]
95
+ percent = abs(change) * 100
96
+ if 99 <= percent < 100:
97
+ percent_text = f"{int(percent * 10) / 10:.1f}%" # never rounds up to "100%"
98
+ else:
99
+ percent_text = f"{percent:,.0f}%" if percent >= 10 else f"{percent:,.1f}%"
100
+ ratio = max(before, after) / min(before, after) if min(before, after) > 0 else None
101
+ times = f" ({ratio:,.1f}×)" if ratio and ratio >= 1.5 else ""
102
+ text = f"{percent_text} {word}{times}"
103
+ return (GOOD if improved else BAD), text, text
104
+
105
+
106
+ def render(spec, out_path):
107
+ rows = spec["rows"]
108
+ for row in rows:
109
+ if float(row["before"]) < 0 or float(row["after"]) < 0:
110
+ sys.exit(f"row {row['label']!r}: negative values are not supported (bars start at zero).")
111
+ band = band_of(spec)
112
+ arms = spec.get("arms", ["Before", "After"])
113
+ count = len(rows)
114
+ headline_lines = textwrap.wrap(spec["headline"], 54)
115
+ head = 0.75 + 0.45 * len(headline_lines)
116
+ height = head + 0.6 + 1.25 * count + (0.5 if spec.get("note") else 0.2)
117
+ fig = plt.figure(figsize=(10, height), dpi=160, facecolor=BACKGROUND)
118
+ ax = fig.add_axes([0, 0, 1, 1])
119
+ ax.set_xlim(0, 10)
120
+ ax.set_ylim(0, height)
121
+ ax.axis("off")
122
+ ax.set_facecolor(BACKGROUND)
123
+
124
+ top = height - 0.3
125
+ ax.text(0.4, top, "\n".join(headline_lines), color=TEXT, fontsize=19, fontweight="bold",
126
+ va="top", linespacing=1.25)
127
+ ax.text(0.4, top - 0.4 * len(headline_lines) - 0.2, spec.get("workload", ""), color=MUTED,
128
+ fontsize=10.5, va="top")
129
+
130
+ arm_right, bar_left, bar_span = 1.35, 1.5, 5.6
131
+ y = height - head - 0.45
132
+ alts = []
133
+ for row in rows:
134
+ before, after = float(row["before"]), float(row["after"])
135
+ unit = row.get("unit", "")
136
+ suffix = f" {unit}" if unit else ""
137
+ color, badge, alt_badge = judge(row, band)
138
+ top_value = max(before, after) or 1.0
139
+ ax.text(0.4, y, row["label"], color=TEXT, fontsize=12.5, fontweight="bold", va="center")
140
+ ax.text(9.6, y, badge, color=color, fontsize=15, fontweight="bold", va="center", ha="right")
141
+ if row.get("note"):
142
+ ax.text(0.4, y - 0.24, row["note"], color=MUTED, fontsize=9, va="center")
143
+ bars = ((arms[0], before, BEFORE), (arms[1], after, color))
144
+ for index, (arm, value, bar_color) in enumerate(bars):
145
+ bar_y = y - 0.5 - index * 0.32
146
+ width = max(bar_span * value / top_value, 0.03)
147
+ ax.add_patch(FancyBboxPatch((bar_left, bar_y - 0.11), width, 0.22,
148
+ boxstyle="round,pad=0,rounding_size=0.04",
149
+ linewidth=0, facecolor=bar_color))
150
+ ax.text(arm_right, bar_y, arm, color=MUTED, fontsize=9.5, va="center", ha="right")
151
+ ax.text(bar_left + width + 0.12, bar_y, f"{fmt(value)}{suffix}", color=TEXT,
152
+ fontsize=10.5, va="center")
153
+ row_alt = f"{row['label']}: {fmt(before)}{suffix} to {fmt(after)}{suffix}, {alt_badge}"
154
+ if row.get("note"):
155
+ row_alt += f" ({row['note']})"
156
+ alts.append(row_alt)
157
+ y -= 1.25
158
+
159
+ if spec.get("note"):
160
+ ax.text(0.4, 0.3, spec["note"], color=MUTED, fontsize=9.5, va="center")
161
+ fig.savefig(out_path, facecolor=BACKGROUND)
162
+ plt.close(fig)
163
+ lead = spec["headline"] + (f". {spec['note']}" if spec.get("note") else "")
164
+ if spec.get("workload"):
165
+ lead += f". Workload: {spec['workload']}"
166
+ return f"{lead}. " + "; ".join(alts) + "."
167
+
168
+
169
+ def table(spec):
170
+ band = band_of(spec)
171
+ arms = spec.get("arms", ["Before", "After"])
172
+ lines = [f"| Metric | {arms[0]} | {arms[1]} | Change |", "| --- | ---: | ---: | --- |"]
173
+ for row in spec["rows"]:
174
+ suffix = f" {row['unit']}" if row.get("unit") else ""
175
+ change = judge(row, band)[2]
176
+ label = row["label"].replace("|", "\\|")
177
+ lines.append(f"| {label} | {fmt(float(row['before']))}{suffix} | "
178
+ f"{fmt(float(row['after']))}{suffix} | {change} |")
179
+ notes = [f"Workload: {spec['workload']}"] if spec.get("workload") else []
180
+ notes += [spec["note"]] if spec.get("note") else []
181
+ notes += [f"{row['label']}: {row['note']}" for row in spec["rows"] if row.get("note")]
182
+ if notes:
183
+ lines += ["", *notes]
184
+ return "\n".join(lines)
185
+
186
+
187
+ def main():
188
+ args = [a for a in sys.argv[1:] if a != "--table"]
189
+ if len(args) != 2:
190
+ sys.exit(__doc__)
191
+ with open(args[0]) as handle:
192
+ spec = json.load(handle)
193
+ print(render(spec, args[1]))
194
+ if "--table" in sys.argv[1:]:
195
+ print()
196
+ print(table(spec))
197
+
198
+
199
+ if __name__ == "__main__":
200
+ main()
@@ -1,45 +0,0 @@
1
- # npm release setup
2
-
3
- The package name is `@bompus/house-rules`; the executable is `house-rules`.
4
- It has no runtime dependencies or install hooks. Installing the package does
5
- not install skills into an agent host. Composition writes the requested rules
6
- file, its `house-rules-references/` directory when the rules include reference
7
- procedures, and any `--skills-out` directory.
8
-
9
- Keep the `package.json` version, changelog version and `v<version>` tag
10
- identical.
11
-
12
- ## First publication
13
-
14
- This one-time setup applies to 0.11.0, the first published version. The first publication requires an npm account that owns the `bompus` scope.
15
- An earlier publication of another package does not establish current login or
16
- scope access. Authenticate using npm's web login and complete its 2FA approval.
17
- Do not put credentials into the repository or workflow.
18
-
19
- On the selected release commit, run `npm run check:package -- --out <directory>`.
20
- Publish that verified `house-rules.tgz` with `npm publish <tarball> --access public`.
21
- Then configure its trusted publisher on npm for GitHub user `bompus`, repository
22
- `house-rules`, workflow filename `npm-publish.yml`. Enable direct `npm publish`.
23
- The default staged-publication permission alone does not permit this workflow.
24
-
25
- The first GitHub release workflow checks the published tarball integrity and
26
- skips an identical existing version. Different bytes at the same version fail
27
- the workflow. Subsequent versions publish automatically after trusted publisher
28
- setup. Do not create another release solely to test authentication.
29
-
30
- ## Subsequent releases
31
-
32
- Publishing a stable GitHub release triggers `.github/workflows/npm-publish.yml`.
33
- It verifies that the tagged commit belongs to `main`, checks the package version
34
- and dated changelog entry, and checks the packed CLI and skill resources before
35
- publishing the same tarball. Prereleases are excluded.
36
-
37
- The workflow uses a GitHub-hosted runner and npm's OIDC trusted publishing.
38
- It stores no npm token. npm requires Node 22.14 or newer and npm 11.5.1 or newer;
39
- the workflow uses Node 26. npm automatically supplies provenance for this public
40
- repository and package. See the [official trusted publishing documentation](https://docs.npmjs.com/trusted-publishers/).
41
-
42
- CI runs `npm run check:package -- --bun`. It installs the actual local tarball
43
- into isolated scratch with lifecycle scripts disabled, exercises the CLI under
44
- Node and Bun, and compares composed skills and resources with the source.
45
- Scratch honors `HOUSE_RULES_TEST_TMP` and is removed when the check exits normally.
@@ -1,12 +0,0 @@
1
- ---
2
- description: Locate Swarmail-owned instructions and tool contracts for local session coordination.
3
- after: Coordination and isolation
4
- ---
5
-
6
- ## Swarmail coordination
7
-
8
- When Swarmail is connected, read its server instructions and tool contracts
9
- before using it. If those instructions are unavailable or omit a needed detail,
10
- read `swarmail --help` and `README.md` in its owning checkout at the installed
11
- or host-approved revision. If available sources do not establish that detail,
12
- report it as unverified rather than guessing the product's operations.
@@ -1,115 +0,0 @@
1
- # CPU priority findings: 2026-10-06
2
-
3
- Read this record before answering whether negative, zero or positive nice values
4
- improved the tested workload. Reuse these results for the same question; a new
5
- experiment needs a materially different workload, contention regime or hypothesis.
6
- Follow the host's authorization rules before changing priority or measuring again.
7
-
8
- ## Result and scope
9
-
10
- Negative nice did not establish a timing or memory benefit in this small WSL
11
- allocation experiment. Verified effective nice 0 was the only setting that met
12
- the preset variation criterion for both runtimes. It is a baseline candidate for
13
- comparable isolated measurements, not a universal priority policy.
14
-
15
- The workload performed 16,384 warmup and 65,536 measured `Buffer.alloc(size, 1)`
16
- operations, cycling 1,000, 16,000, 128,000 and 1,000,000-byte buffers and retaining
17
- at most 128 references. Timing and CPU cover the measured loop; peak RSS covers
18
- the whole process. This allocation case is also reported in
19
- [Bun issue 44661](https://github.com/oven-sh/bun/issues/44661).
20
- This is a priority sensitivity comparison, not a general Bun-versus-Node ranking,
21
- a contention-resistance test or an explanation of that issue's root cause.
22
-
23
- ## Recorded experiment
24
-
25
- The measured interval was 2026-10-06 23:42:55Z–23:45:40Z. Bun 1.4.2 and
26
- Node 26.10.0 used unchanged sources and binaries. Three independent processes
27
- per runtime/priority cell ran in counterbalanced order, for 24 processes total.
28
- All passed correctness, effective-control and quiet-host admission checks;
29
- none was rejected. The preset criterion was `(maximum - minimum) / median <= 10%`.
30
-
31
- Controls were Windows-hosted WSL, Linux kernel 7.2.8 with an unverified custom
32
- scheduler implementation, ordinary fair scheduling, unprivileged workload UID
33
- 1000, CPU affinity 0–7 and identical 704 MiB `memory.high`/`memory.max` limits.
34
- No CPU quota was present at inspected cgroup ancestors. The launcher set absolute
35
- priority before dropping privileges and verified it afterward; the workload did
36
- not run as root. Main-thread scheduler wait included warmup and cannot establish
37
- timed-region or all-GC-thread scheduling effects.
38
-
39
- | Runtime | Nice | Median wall ms | Wall range ms | Span | Median CPU ms | Median peak RSS MiB | Variation passes |
40
- | ------- | ---: | -------------: | ------------: | -----: | ------------: | ------------------: | ---------------- |
41
- | bun | +10 | 1445.9 | 1195.6–1467.9 | 18.83% | 1812.3 | 191.5 | no |
42
- | bun | +0 | 1356.4 | 1326.5–1412.4 | 6.34% | 1778.9 | 191.3 | yes |
43
- | bun | -10 | 1416.1 | 1291.2–1468.1 | 12.49% | 1781.2 | 189.2 | no |
44
- | bun | -20 | 1346.1 | 1287.4–1497.2 | 15.58% | 1691.4 | 190.1 | no |
45
- | node | +10 | 1196.5 | 1083.8–1231.8 | 12.37% | 1849.8 | 193.5 | no |
46
- | node | +0 | 1136.2 | 1133.3–1138.5 | 0.46% | 1735.8 | 192.1 | yes |
47
- | node | -10 | 1148.1 | 1097.3–1152.7 | 4.82% | 1747.0 | 191.9 | yes |
48
- | node | -20 | 1191.7 | 1189.9–1277.3 | 7.33% | 1825.9 | 192.7 | yes |
49
-
50
- Bun +10, -10 and -20 failed the variation criterion. Node -10 overlapped nice 0;
51
- Node -20 was slower. These three-process samples support no confirmed negative
52
- priority gain. The small quiet-host cohort does not predict behavior under
53
- contention or on another scheduler. The per-process measurement values below
54
- make the reported aggregates auditable; their scope limits still apply.
55
-
56
- ## Per-process measurement values
57
-
58
- These are the 24 retained output measurements used above, with path and process
59
- identity fields omitted. Repetition numbers identify each process within its
60
- runtime/priority cell; they are not execution order. CPU is in microseconds and
61
- peak RSS in KiB to retain the source units. Wall values retain nine decimal
62
- places for aggregate recalculation, not a claim of clock accuracy.
63
-
64
- Recalculation from these samples matches every aggregate before display rounding.
65
- Each source output passed correctness and effective-control checks before and
66
- after the workload. No process was rejected. The broader host-admission receipts
67
- remain outside this bundle; this table provides sample-level auditability for
68
- the reported wall, CPU, RSS and variation values, not complete host reproduction.
69
-
70
- | Runtime | Nice | Repetition | Wall ms | CPU us | Peak RSS KiB |
71
- | ------- | ---: | ---------: | -------------: | ------: | -----------: |
72
- | bun | +10 | 1 | 1195.596419000 | 1505936 | 196116 |
73
- | bun | +10 | 2 | 1445.887323000 | 1812345 | 190948 |
74
- | bun | +10 | 3 | 1467.863081000 | 1852217 | 197132 |
75
- | bun | +0 | 1 | 1326.456355000 | 1659644 | 195900 |
76
- | bun | +0 | 2 | 1412.394017000 | 1778913 | 189540 |
77
- | bun | +0 | 3 | 1356.414170000 | 1779749 | 199772 |
78
- | bun | -10 | 1 | 1291.186539000 | 1638686 | 190644 |
79
- | bun | -10 | 2 | 1468.095042000 | 1847875 | 195332 |
80
- | bun | -10 | 3 | 1416.096128000 | 1781215 | 193692 |
81
- | bun | -20 | 1 | 1287.427399000 | 1628746 | 194676 |
82
- | bun | -20 | 2 | 1497.167736000 | 1893806 | 191196 |
83
- | bun | -20 | 3 | 1346.090557000 | 1691437 | 195036 |
84
- | node | +10 | 1 | 1083.811791000 | 1655921 | 200988 |
85
- | node | +10 | 2 | 1196.507378000 | 1849814 | 198100 |
86
- | node | +10 | 3 | 1231.812016000 | 1913550 | 197184 |
87
- | node | +0 | 1 | 1138.547173000 | 1717254 | 196524 |
88
- | node | +0 | 2 | 1136.151985000 | 1735839 | 197480 |
89
- | node | +0 | 3 | 1133.265512000 | 1736305 | 196716 |
90
- | node | -10 | 1 | 1097.328563000 | 1684817 | 196008 |
91
- | node | -10 | 2 | 1152.692612000 | 1789165 | 197780 |
92
- | node | -10 | 3 | 1148.141853000 | 1746972 | 196516 |
93
- | node | -20 | 1 | 1277.348138000 | 1994581 | 196600 |
94
- | node | -20 | 2 | 1191.670413000 | 1825925 | 197344 |
95
- | node | -20 | 3 | 1189.945316000 | 1821113 | 198976 |
96
-
97
- ## Omitting nice versus requesting zero
98
-
99
- A child inherits its parent's nice value, and `exec` preserves it. Omitting
100
- `nice` therefore yields zero only when the parent already has effective nice 0.
101
- GNU `nice -n 0 COMMAND` adds zero to the inherited value; it does not reset +10
102
- to zero. Bare `nice COMMAND` applies the default +10 adjustment. `setpriority`
103
- sets an absolute value, subject to permissions; verify the effective value
104
- rather than treating the requested command as proof.
105
-
106
- Positive nice lowers CPU scheduling priority; negative nice raises it. Neither
107
- reserves a core or replaces host admission and resource controls. Keep effective
108
- values equal across ordinary comparison arms. General +10 background/build
109
- policies serve responsiveness and are separate from this experiment; these
110
- results do not authorize removing them or changing installed settings.
111
-
112
- Sources: [Linux getpriority/setpriority](https://man7.org/linux/man-pages/man2/setpriority.2.html)
113
- for inheritance, absolute values and permissions; [GNU nice](https://www.gnu.org/software/coreutils/manual/html_node/nice-invocation.html)
114
- for relative adjustment. GNU online retrieval was unavailable during verification;
115
- the installed command's help confirmed the adjustment and default +10.
@@ -1,5 +0,0 @@
1
- interface:
2
- display_name: "HR: Change impact"
3
- short_description: "Check what a change could break before merging"
4
- policy:
5
- allow_implicit_invocation: false