@bompus/house-rules 0.0.0-stage → 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.
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +54 -0
- package/LICENSE +21 -0
- package/README.md +378 -2
- package/THIRD_PARTY_NOTICES.md +188 -0
- package/compose.mjs +125 -0
- package/composition.mjs +361 -0
- package/config-view.mjs +209 -0
- package/config.mjs +381 -0
- package/docs/assets/banner-dark.png +0 -0
- package/docs/assets/banner-light.png +0 -0
- package/docs/assets/overview.png +0 -0
- package/docs/configuration.md +269 -0
- package/docs/skill-names.md +50 -0
- package/examples/person/house-rules.json +15 -0
- package/examples/person/rules/10-tooling.md +8 -0
- package/examples/person/rules/20-reporting.md +9 -0
- package/examples/project/AGENTS.md +18 -0
- package/package.json +42 -4
- package/rule-references.mjs +91 -0
- package/rules/core.md +340 -0
- package/rules/modifiers/backlog-outline.md +25 -0
- package/rules/modifiers/backlog-visual.md +16 -0
- package/rules/modifiers/coded-offers.md +70 -0
- package/rules/modifiers/cross-session-relay.md +23 -0
- package/rules/modifiers/effort-estimates.md +41 -0
- package/rules/modifiers/land-when-done.md +12 -0
- package/rules/modifiers/low-quota-handoff.md +20 -0
- package/rules/modifiers/model-default-questions.md +33 -0
- package/rules/modifiers/multi-agent.md +38 -0
- package/rules/modifiers/no-attribution.md +16 -0
- package/rules/modifiers/periodic-updates.md +25 -0
- package/rules/modifiers/plan-files.md +82 -0
- package/rules/modifiers/question-cards.md +48 -0
- package/rules/modifiers/release-batching.md +15 -0
- package/rules/modifiers/scratch-on-disk.md +15 -0
- package/rules/modifiers/shared-host-load.md +19 -0
- package/rules/modifiers/solo-operator.md +13 -0
- package/rules/modifiers/squash-landing.md +22 -0
- package/rules/modifiers/upstream-contributions.md +45 -0
- package/rules/modifiers/web-image-formats.md +35 -0
- package/rules/references/backlog-view.md +154 -0
- package/rules/references/github-actions.md +45 -0
- package/rules/references/landing.md +39 -0
- package/rules/references/multi-agent.md +51 -0
- package/rules/references/release-batching.md +66 -0
- package/rules/references/squash-landing.md +50 -0
- package/rules/references/thread-visuals.md +45 -0
- package/setup.mjs +445 -0
- package/skills/hr-agent-guidance-audit/LICENSE +21 -0
- package/skills/hr-agent-guidance-audit/SKILL.md +91 -0
- package/skills/hr-agent-guidance-audit/agents/openai.yaml +2 -0
- package/skills/hr-agent-guidance-audit/references/prune-workflow.md +72 -0
- package/skills/hr-agent-guidance-audit/references/records-and-lessons.md +60 -0
- package/skills/hr-agent-guidance-audit/references/retirement-verdicts.md +49 -0
- package/skills/hr-agent-guidance-refresh/LICENSE +21 -0
- package/skills/hr-agent-guidance-refresh/SKILL.md +36 -0
- package/skills/hr-agent-guidance-refresh/agents/openai.yaml +2 -0
- package/skills/hr-agent-guidance-refresh/references/verification.md +47 -0
- package/skills/hr-api-exposure-check/SKILL.md +159 -0
- package/skills/hr-api-exposure-check/agents/openai.yaml +3 -0
- package/skills/hr-audit-choices/SKILL.md +67 -0
- package/skills/hr-audit-choices/agents/openai.yaml +2 -0
- package/skills/hr-benchmarking/NOTICE.md +36 -0
- package/skills/hr-benchmarking/SKILL.md +279 -0
- package/skills/hr-benchmarking/agents/openai.yaml +2 -0
- package/skills/hr-benchmarking/references/javascript.md +130 -0
- package/skills/hr-benchmarking/references/tools.md +165 -0
- package/skills/hr-benchmarking/scripts/process-attribution.ps1 +20 -0
- package/skills/hr-benchmarking/scripts/process-attribution.py +107 -0
- package/skills/hr-better-accessibility/LICENSE +22 -0
- package/skills/hr-better-accessibility/NOTICE.md +46 -0
- package/skills/hr-better-accessibility/SKILL.md +119 -0
- package/skills/hr-better-accessibility/agents/openai.yaml +3 -0
- package/skills/hr-better-accessibility/focus-and-keyboard.md +130 -0
- package/skills/hr-better-accessibility/forms.md +82 -0
- package/skills/hr-better-accessibility/hit-areas.md +98 -0
- package/skills/hr-better-accessibility/motion-and-zoom.md +81 -0
- package/skills/hr-better-accessibility/screen-readers.md +102 -0
- package/skills/hr-better-accessibility/semantics-and-aria.md +84 -0
- package/skills/hr-better-colors/LICENSE +21 -0
- package/skills/hr-better-colors/NOTICE.md +37 -0
- package/skills/hr-better-colors/SKILL.md +114 -0
- package/skills/hr-better-colors/agents/openai.yaml +3 -0
- package/skills/hr-better-colors/color-formats.md +90 -0
- package/skills/hr-better-colors/color-usage.md +140 -0
- package/skills/hr-better-colors/contrast.md +80 -0
- package/skills/hr-better-colors/palette-generation.md +104 -0
- package/skills/hr-better-colors/palette-structure.md +76 -0
- package/skills/hr-better-colors/token-naming.md +97 -0
- package/skills/hr-better-layout/LICENSE +22 -0
- package/skills/hr-better-layout/NOTICE.md +48 -0
- package/skills/hr-better-layout/SKILL.md +92 -0
- package/skills/hr-better-layout/agents/openai.yaml +3 -0
- package/skills/hr-better-layout/grouping-and-alignment.md +144 -0
- package/skills/hr-better-layout/spacing-and-adaptivity.md +215 -0
- package/skills/hr-better-typography/LICENSE +22 -0
- package/skills/hr-better-typography/NOTICE.md +46 -0
- package/skills/hr-better-typography/SKILL.md +172 -0
- package/skills/hr-better-typography/agents/openai.yaml +3 -0
- package/skills/hr-better-typography/choosing-fonts.md +69 -0
- package/skills/hr-better-typography/css-cheat-sheet.md +65 -0
- package/skills/hr-better-typography/details-and-accessibility.md +119 -0
- package/skills/hr-better-typography/spacing-and-sizing.md +131 -0
- package/skills/hr-better-typography/variable-fonts-and-opentype.md +105 -0
- package/skills/hr-better-typography/wrapping-and-punctuation.md +57 -0
- package/skills/hr-better-writing/LICENSE +22 -0
- package/skills/hr-better-writing/NOTICE.md +46 -0
- package/skills/hr-better-writing/SKILL.md +122 -0
- package/skills/hr-better-writing/agents/openai.yaml +3 -0
- package/skills/hr-code-review/LICENSE +21 -0
- package/skills/hr-code-review/NOTICE.md +26 -0
- package/skills/hr-code-review/SKILL.md +163 -0
- package/skills/hr-code-review/agents/openai.yaml +3 -0
- package/skills/hr-code-review/references/acp-client.md +43 -0
- package/skills/hr-code-review/references/evidence.md +57 -0
- package/skills/hr-code-review/references/impact.md +103 -0
- package/skills/hr-code-review/references/panel-adjudication.md +58 -0
- package/skills/hr-code-review/references/panel-plan.md +61 -0
- package/skills/hr-code-review/references/panel-recommendations.json +105 -0
- package/skills/hr-code-review/references/panel-recommendations.md +46 -0
- package/skills/hr-code-review/references/panel-setup.md +54 -0
- package/skills/hr-code-review/references/reviewer-role.md +31 -0
- package/skills/hr-code-review/scripts/acp-panel-client.mjs +299 -0
- package/skills/hr-code-review/scripts/check-receipts.mjs +263 -0
- package/skills/hr-code-review/scripts/panel-plan.mjs +69 -0
- package/skills/hr-code-review/scripts/panel-preferences.mjs +220 -0
- package/skills/hr-design-exploration/SKILL.md +105 -0
- package/skills/hr-design-exploration/agents/openai.yaml +4 -0
- package/skills/hr-diagnosing-bugs/NOTICE.md +45 -0
- package/skills/hr-diagnosing-bugs/SKILL.md +108 -0
- package/skills/hr-diagnosing-bugs/agents/openai.yaml +3 -0
- package/skills/hr-diagnosing-bugs/references/reporting.md +97 -0
- package/skills/hr-diagnosing-bugs/scripts/check-pr-offer.mjs +47 -0
- package/skills/hr-explain-code/NOTICE.md +37 -0
- package/skills/hr-explain-code/SKILL.md +110 -0
- package/skills/hr-explain-code/agents/openai.yaml +5 -0
- package/skills/hr-explain-code/references/helper-brief.md +39 -0
- package/skills/hr-extract-shared-steps/SKILL.md +134 -0
- package/skills/hr-extract-shared-steps/agents/openai.yaml +3 -0
- package/skills/hr-forgotten-work-audit/SKILL.md +130 -0
- package/skills/hr-forgotten-work-audit/references/brief-template.md +56 -0
- package/skills/hr-forgotten-work-audit/references/result-format.md +46 -0
- package/skills/hr-handoff/LICENSE +21 -0
- package/skills/hr-handoff/NOTICE.md +29 -0
- package/skills/hr-handoff/SKILL.md +114 -0
- package/skills/hr-handoff/agents/openai.yaml +5 -0
- package/skills/hr-handoff/assets/ledger.example.json +10 -0
- package/skills/hr-handoff/assets/receipt.example.json +76 -0
- package/skills/hr-handoff/assets/source.example.json +20 -0
- package/skills/hr-handoff/references/reconciliation.md +124 -0
- package/skills/hr-handoff/references/successor-thread.md +76 -0
- package/skills/hr-handoff/scripts/check-reconciliation.mjs +324 -0
- package/skills/hr-house-rules-setup/SKILL.md +114 -0
- package/skills/hr-house-rules-setup/agents/openai.yaml +5 -0
- package/skills/hr-issue-tracker-setup/SKILL.md +49 -0
- package/skills/hr-issue-tracker-setup/agents/openai.yaml +5 -0
- package/skills/hr-lean-plan/SKILL.md +146 -0
- package/skills/hr-lean-plan/agents/openai.yaml +5 -0
- package/skills/hr-maintainability-review/SKILL.md +186 -0
- package/skills/hr-maintainability-review/agents/openai.yaml +5 -0
- package/skills/hr-manual-qa/NOTICE.md +36 -0
- package/skills/hr-manual-qa/SKILL.md +37 -0
- package/skills/hr-manual-qa/agents/openai.yaml +3 -0
- package/skills/hr-navigation-retro/LICENSE +21 -0
- package/skills/hr-navigation-retro/NOTICE.md +5 -0
- package/skills/hr-navigation-retro/SKILL.md +86 -0
- package/skills/hr-navigation-retro/agents/openai.yaml +4 -0
- package/skills/hr-navigation-retro/references/inputs.md +67 -0
- package/skills/hr-navigation-retro/scripts/retro.py +552 -0
- package/skills/hr-navigation-retro/scripts/transcripts.py +205 -0
- package/skills/hr-ordering-tests/SKILL.md +51 -0
- package/skills/hr-ordering-tests/agents/openai.yaml +2 -0
- package/skills/hr-plain-prose/SKILL.md +264 -0
- package/skills/hr-plain-prose/agents/openai.yaml +3 -0
- package/skills/hr-plain-prose/scripts/check.mjs +331 -0
- package/skills/hr-pr-followup/LICENSE +21 -0
- package/skills/hr-pr-followup/NOTICE.md +9 -0
- package/skills/hr-pr-followup/SKILL.md +74 -0
- package/skills/hr-pr-followup/agents/openai.yaml +2 -0
- package/skills/hr-pr-followup/references/review-helpers.md +111 -0
- package/skills/hr-pr-followup/scripts/check-landing.py +204 -0
- package/skills/hr-pr-followup/scripts/check-pr-review.ts +510 -0
- package/skills/hr-pr-followup/scripts/merge-pr.sh +100 -0
- package/skills/hr-pr-followup/scripts/resolve-pr-thread.ts +219 -0
- package/skills/hr-pr-followup/scripts/verify-landed.sh +184 -0
- package/skills/hr-progress-report/SKILL.md +49 -0
- package/skills/hr-progress-report/agents/openai.yaml +5 -0
- package/skills/hr-read-reddit/SKILL.md +44 -0
- package/skills/hr-read-reddit/agents/openai.yaml +2 -0
- package/skills/hr-read-reddit/scripts/reddit.ts +252 -0
- package/skills/hr-read-x-links/SKILL.md +42 -0
- package/skills/hr-read-x-links/agents/openai.yaml +2 -0
- package/skills/hr-read-x-links/scripts/x-post.ts +264 -0
- package/skills/hr-research-shared-links/SKILL.md +103 -0
- package/skills/hr-split-to-prs/LICENSE +21 -0
- package/skills/hr-split-to-prs/NOTICE.md +9 -0
- package/skills/hr-split-to-prs/SKILL.md +61 -0
- package/skills/hr-split-to-prs/agents/openai.yaml +2 -0
- package/skills/hr-sqlite/SKILL.md +174 -0
- package/skills/hr-sqlite/agents/openai.yaml +2 -0
- package/skills/hr-sqlite/references/evidence.md +94 -0
- package/skills/hr-sqlite/references/tool-decisions.md +39 -0
- package/skills/hr-sqlite/scripts/inspect-sqlite.py +245 -0
- package/skills/hr-stock-ui-audit/SKILL.md +132 -0
- package/skills/hr-stock-ui-audit/agents/openai.yaml +3 -0
- package/skills/hr-stock-ui-audit/scripts/scan.mjs +619 -0
- package/skills/hr-tdd/LICENSE +21 -0
- package/skills/hr-tdd/NOTICE.md +10 -0
- package/skills/hr-tdd/SKILL.md +40 -0
- package/skills/hr-tdd/agents/openai.yaml +3 -0
- package/skills/hr-tdd/mocking.md +39 -0
- package/skills/hr-tdd/tests.md +77 -0
- package/skills/hr-test-audit/LICENSE +21 -0
- package/skills/hr-test-audit/NOTICE.md +67 -0
- package/skills/hr-test-audit/SKILL.md +146 -0
- package/skills/hr-test-audit/agents/openai.yaml +3 -0
- package/skills/hr-test-audit/scripts/floor-guard.ts +137 -0
- package/skills/hr-usage-report/SKILL.md +90 -0
- package/skills/hr-usage-report/agents/openai.yaml +2 -0
- package/skills/hr-usage-report/assets/example-report.json +125 -0
- package/skills/hr-usage-report/assets/report-template.html +377 -0
- package/skills/hr-usage-report/scripts/render-report.ts +86 -0
- package/skills/hr-usage-report/scripts/usage-by-model.ts +499 -0
- package/skills/hr-what-next/SKILL.md +151 -0
- package/skills/hr-what-next/agents/openai.yaml +4 -0
- package/skills/hr-what-next/references/reporting.md +59 -0
- package/skills/hr-what-next/scripts/check-open-work.mjs +711 -0
- package/skills/hr-writing-for-agents/NOTICE.md +46 -0
- package/skills/hr-writing-for-agents/SKILL-MECHANICS.md +83 -0
- package/skills/hr-writing-for-agents/SKILL.md +108 -0
- package/skills/hr-writing-for-agents/agents/openai.yaml +3 -0
- package/skills/hr-writing-pr/NOTICE.md +48 -0
- package/skills/hr-writing-pr/SKILL.md +119 -0
- package/skills/hr-writing-pr/agents/openai.yaml +2 -0
- package/skills/hr-writing-pr/scripts/benefit-chart.py +200 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// Portable panel preferences and a pure resolver. See ../references/panel-plan.md.
|
|
2
|
+
// Exact model/provider bindings come from a user-owned file; nothing here calls a model.
|
|
3
|
+
const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4
|
+
const alias = /^[a-z][a-z0-9-]{0,63}$/;
|
|
5
|
+
|
|
6
|
+
function keys(value, required, optional, path) {
|
|
7
|
+
if (!object(value)) throw new Error(`${path} must be an object`);
|
|
8
|
+
for (const key of required)
|
|
9
|
+
if (!Object.hasOwn(value, key)) throw new Error(`${path}.${key} is required`);
|
|
10
|
+
for (const key of Object.keys(value))
|
|
11
|
+
if (![...required, ...optional].includes(key)) throw new Error(`unknown ${path}.${key}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function validatePanelPreferences(value) {
|
|
15
|
+
keys(value, ["version", "roles", "policy"], ["profile"], "panel");
|
|
16
|
+
if (value.version !== 1) throw new Error("panel.version must be 1");
|
|
17
|
+
if (value.profile !== undefined && !["quick", "balanced", "deep"].includes(value.profile))
|
|
18
|
+
throw new Error("panel.profile must be quick, balanced or deep");
|
|
19
|
+
if (!Array.isArray(value.roles) || value.roles.length === 0)
|
|
20
|
+
throw new Error("panel.roles must be a non-empty array");
|
|
21
|
+
const ids = new Set();
|
|
22
|
+
for (const [index, role] of value.roles.entries()) {
|
|
23
|
+
const path = `panel.roles[${index}]`;
|
|
24
|
+
keys(role, ["id", "candidates"], [], path);
|
|
25
|
+
if (typeof role.id !== "string" || !alias.test(role.id))
|
|
26
|
+
throw new Error(`${path}.id must be a lowercase alias (letters, digits and hyphens)`);
|
|
27
|
+
if (ids.has(role.id)) throw new Error(`duplicate panel role "${role.id}"`);
|
|
28
|
+
ids.add(role.id);
|
|
29
|
+
if (
|
|
30
|
+
!Array.isArray(role.candidates) ||
|
|
31
|
+
role.candidates.length === 0 ||
|
|
32
|
+
role.candidates.some((candidate) => typeof candidate !== "string" || !alias.test(candidate))
|
|
33
|
+
)
|
|
34
|
+
throw new Error(`${path}.candidates must be a non-empty array of lowercase aliases`);
|
|
35
|
+
if (new Set(role.candidates).size !== role.candidates.length)
|
|
36
|
+
throw new Error(`${path}.candidates contains duplicates`);
|
|
37
|
+
}
|
|
38
|
+
keys(
|
|
39
|
+
value.policy,
|
|
40
|
+
["fallback", "roundLimit", "meteredRoutes"],
|
|
41
|
+
["distinctFamilies", "excludeAuthorFamily", "allowReducedPanel"],
|
|
42
|
+
"panel.policy",
|
|
43
|
+
);
|
|
44
|
+
for (const key of ["distinctFamilies", "excludeAuthorFamily", "allowReducedPanel"])
|
|
45
|
+
if (value.policy[key] !== undefined && typeof value.policy[key] !== "boolean")
|
|
46
|
+
throw new Error(`panel.policy.${key} must be boolean`);
|
|
47
|
+
if (!["none", "approved-only"].includes(value.policy.fallback))
|
|
48
|
+
throw new Error("panel.policy.fallback must be none or approved-only");
|
|
49
|
+
if (!Number.isSafeInteger(value.policy.roundLimit) || value.policy.roundLimit < 1)
|
|
50
|
+
throw new Error("panel.policy.roundLimit must be a positive safe integer");
|
|
51
|
+
if (!["included-only", "explicit-approval-required"].includes(value.policy.meteredRoutes))
|
|
52
|
+
throw new Error(
|
|
53
|
+
"panel.policy.meteredRoutes must be included-only or explicit-approval-required",
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function changePanelPreferences(config, value) {
|
|
58
|
+
validatePanelPreferences(value);
|
|
59
|
+
return { ...structuredClone(config), panel: structuredClone(value) };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const familyName = /^[a-z][a-z0-9-]{0,63}$/;
|
|
63
|
+
|
|
64
|
+
export function validatePanelBindings(value) {
|
|
65
|
+
keys(value, ["version", "aliases"], [], "bindings");
|
|
66
|
+
if (value.version !== 1) throw new Error("bindings.version must be 1");
|
|
67
|
+
if (!object(value.aliases)) throw new Error("bindings.aliases must be an object");
|
|
68
|
+
for (const [name, binding] of Object.entries(value.aliases)) {
|
|
69
|
+
const path = `bindings.aliases.${name}`;
|
|
70
|
+
if (!alias.test(name))
|
|
71
|
+
throw new Error(`${path}: alias must be lowercase letters, digits and hyphens`);
|
|
72
|
+
keys(binding, ["launch"], ["families", "metered"], path);
|
|
73
|
+
if (!object(binding.launch) || Object.keys(binding.launch).length === 0)
|
|
74
|
+
throw new Error(`${path}.launch must be a non-empty object`);
|
|
75
|
+
if (
|
|
76
|
+
binding.families !== undefined &&
|
|
77
|
+
(!Array.isArray(binding.families) ||
|
|
78
|
+
binding.families.length === 0 ||
|
|
79
|
+
binding.families.some((family) => typeof family !== "string" || !familyName.test(family)) ||
|
|
80
|
+
new Set(binding.families).size !== binding.families.length)
|
|
81
|
+
)
|
|
82
|
+
throw new Error(`${path}.families must be a non-empty array of distinct lowercase names`);
|
|
83
|
+
if (binding.metered !== undefined && typeof binding.metered !== "boolean")
|
|
84
|
+
throw new Error(`${path}.metered must be boolean`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Project and task layers may only tighten the user's policy.
|
|
89
|
+
function combinePolicy(layers) {
|
|
90
|
+
const policies = layers.map((layer) => layer.policy);
|
|
91
|
+
const [user] = policies;
|
|
92
|
+
return {
|
|
93
|
+
fallback: policies.some((p) => p.fallback === "none") ? "none" : "approved-only",
|
|
94
|
+
roundLimit: Math.min(...policies.map((p) => p.roundLimit)),
|
|
95
|
+
meteredRoutes: policies.some((p) => p.meteredRoutes === "included-only")
|
|
96
|
+
? "included-only"
|
|
97
|
+
: "explicit-approval-required",
|
|
98
|
+
distinctFamilies: policies.some((p) => p.distinctFamilies === true),
|
|
99
|
+
excludeAuthorFamily: policies.some((p) => p.excludeAuthorFamily === true),
|
|
100
|
+
allowReducedPanel:
|
|
101
|
+
user.allowReducedPanel === true && policies.every((p) => p.allowReducedPanel !== false),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// A later layer replaces a role's whole ordered candidate list; new role ids append.
|
|
106
|
+
function combineRoles(layers) {
|
|
107
|
+
const roles = new Map();
|
|
108
|
+
for (const layer of layers)
|
|
109
|
+
for (const role of layer.roles) roles.set(role.id, [...role.candidates]);
|
|
110
|
+
return [...roles].map(([id, candidates]) => ({ id, candidates }));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function assign(roles, index, taken, chosen, distinct) {
|
|
114
|
+
if (index === roles.length) return chosen;
|
|
115
|
+
for (const option of roles[index].options) {
|
|
116
|
+
if (distinct && option.families.some((family) => taken.has(family))) continue;
|
|
117
|
+
const next = assign(
|
|
118
|
+
roles,
|
|
119
|
+
index + 1,
|
|
120
|
+
new Set([...taken, ...option.families]),
|
|
121
|
+
[...chosen, { role: roles[index].id, ...option }],
|
|
122
|
+
distinct,
|
|
123
|
+
);
|
|
124
|
+
if (next) return next;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* request: { user, project?, task?, bindings, authorFamilies?, approvals?: { project?, metered? } }
|
|
131
|
+
* Returns { ok, seats, reduced, rejected, blockers, roundLimit, policy }; never launches a seat.
|
|
132
|
+
*/
|
|
133
|
+
export function resolvePanel(request) {
|
|
134
|
+
const { user, project, task, bindings, authorFamilies = [], approvals = {} } = request;
|
|
135
|
+
validatePanelPreferences(user);
|
|
136
|
+
validatePanelBindings(bindings);
|
|
137
|
+
const blockers = [];
|
|
138
|
+
const layers = [user];
|
|
139
|
+
for (const [name, layer] of [
|
|
140
|
+
["project", project],
|
|
141
|
+
["task", task],
|
|
142
|
+
]) {
|
|
143
|
+
if (layer === undefined) continue;
|
|
144
|
+
validatePanelPreferences(layer);
|
|
145
|
+
if (name === "project" && approvals.project !== true)
|
|
146
|
+
blockers.push({ message: "project panel preferences are not approved" });
|
|
147
|
+
else layers.push(layer);
|
|
148
|
+
}
|
|
149
|
+
const policy = combinePolicy(layers);
|
|
150
|
+
const strictFamilies = policy.distinctFamilies || policy.excludeAuthorFamily;
|
|
151
|
+
if (policy.excludeAuthorFamily && authorFamilies.length === 0)
|
|
152
|
+
blockers.push({ message: "author family is unknown, so it cannot be excluded" });
|
|
153
|
+
const metered = new Set(approvals.metered ?? []);
|
|
154
|
+
const rejected = [];
|
|
155
|
+
const reduced = [];
|
|
156
|
+
const roles = [];
|
|
157
|
+
for (const role of combineRoles(layers)) {
|
|
158
|
+
const options = [];
|
|
159
|
+
const candidates = policy.fallback === "none" ? role.candidates.slice(0, 1) : role.candidates;
|
|
160
|
+
for (const name of candidates) {
|
|
161
|
+
const binding = Object.hasOwn(bindings.aliases, name) ? bindings.aliases[name] : undefined;
|
|
162
|
+
const reject = (reason) => rejected.push({ role: role.id, alias: name, reason });
|
|
163
|
+
if (binding === undefined) reject("no binding for this alias");
|
|
164
|
+
else if (strictFamilies && binding.families === undefined) reject("model family is unknown");
|
|
165
|
+
else if (
|
|
166
|
+
policy.excludeAuthorFamily &&
|
|
167
|
+
binding.families.some((f) => authorFamilies.includes(f))
|
|
168
|
+
)
|
|
169
|
+
reject("shares a model family with the author");
|
|
170
|
+
else if (binding.metered === true && policy.meteredRoutes === "included-only")
|
|
171
|
+
reject("metered route is not allowed by an included-only policy");
|
|
172
|
+
else if (binding.metered === true && !metered.has(name))
|
|
173
|
+
reject("metered route needs explicit approval");
|
|
174
|
+
else
|
|
175
|
+
options.push({
|
|
176
|
+
alias: name,
|
|
177
|
+
families: binding.families ?? [],
|
|
178
|
+
metered: binding.metered === true,
|
|
179
|
+
launch: binding.launch,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (options.length > 0) roles.push({ id: role.id, options });
|
|
183
|
+
else if (policy.allowReducedPanel) reduced.push(role.id);
|
|
184
|
+
else blockers.push({ role: role.id, message: `no eligible route for role "${role.id}"` });
|
|
185
|
+
}
|
|
186
|
+
let seats = [];
|
|
187
|
+
if (blockers.length === 0) {
|
|
188
|
+
if (roles.length === 0) blockers.push({ message: "no role has an eligible route" });
|
|
189
|
+
else {
|
|
190
|
+
seats = assign(roles, 0, new Set(), [], policy.distinctFamilies);
|
|
191
|
+
if (seats === null) {
|
|
192
|
+
seats = [];
|
|
193
|
+
blockers.push({ message: "no assignment gives every seat a distinct model family" });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
ok: blockers.length === 0,
|
|
199
|
+
seats,
|
|
200
|
+
reduced,
|
|
201
|
+
rejected,
|
|
202
|
+
blockers,
|
|
203
|
+
roundLimit: policy.roundLimit,
|
|
204
|
+
policy,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function formatPanelPlan(plan) {
|
|
209
|
+
const lines = [plan.ok ? "Panel plan (no model has been called):" : "Panel blocked:"];
|
|
210
|
+
for (const seat of plan.seats) {
|
|
211
|
+
const families = seat.families.length > 0 ? seat.families.join("+") : "unknown";
|
|
212
|
+
lines.push(` ${seat.role}: ${seat.alias} (${families}${seat.metered ? ", metered" : ""})`);
|
|
213
|
+
}
|
|
214
|
+
for (const role of plan.reduced) lines.push(` ${role}: dropped, no eligible route`);
|
|
215
|
+
for (const blocker of plan.blockers) lines.push(` blocker: ${blocker.message}`);
|
|
216
|
+
for (const item of plan.rejected)
|
|
217
|
+
lines.push(` skipped ${item.alias} for ${item.role}: ${item.reason}`);
|
|
218
|
+
lines.push(` rounds: ${plan.roundLimit}`);
|
|
219
|
+
return lines.join("\n");
|
|
220
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hr-design-exploration
|
|
3
|
+
description: "Explore visual design or redesign alternatives through four ranked directions, top-two feedback and refinement toward one chosen design, or compare variants of one component in place. Use when asked to propose or compare UI design directions or component variants; ordinary UI fixes and implementing a chosen design do not need it."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Design exploration
|
|
7
|
+
|
|
8
|
+
Use the user's requested scope and constraints. The default is four initial
|
|
9
|
+
directions, then rounds containing the two selected designs and one variation
|
|
10
|
+
of each. A requested count applies to the initial comparison unless the user
|
|
11
|
+
also specifies refinement rounds. Refinement defaults to four options. Before
|
|
12
|
+
a differently sized refinement round, agree which selected designs to retain
|
|
13
|
+
and how many variations to show. The user's chosen method takes precedence.
|
|
14
|
+
|
|
15
|
+
## Establish the comparison
|
|
16
|
+
|
|
17
|
+
Read the brief and current design. Identify the intended users, primary task,
|
|
18
|
+
content, required interactions, brand constraints and target viewports. Use
|
|
19
|
+
existing answers; ask only for missing information that would change the
|
|
20
|
+
alternatives. State the goal used to rank recommendations.
|
|
21
|
+
|
|
22
|
+
Keep the same real content, states and viewport sizes across previews. Hold
|
|
23
|
+
accessibility and required behavior constant. If content is unavailable, label
|
|
24
|
+
placeholder content and the assumptions it introduces.
|
|
25
|
+
|
|
26
|
+
## Show the initial directions
|
|
27
|
+
|
|
28
|
+
Create four meaningfully different approaches by default to the same goal. Differences
|
|
29
|
+
should affect hierarchy, layout, navigation, interaction or density. Color
|
|
30
|
+
swaps alone do not make distinct directions. Stay within the authorized
|
|
31
|
+
prototype scope; keep the current implementation available for comparison.
|
|
32
|
+
|
|
33
|
+
Show inspectable previews at comparable sizes, using the host's available
|
|
34
|
+
preview or image tools. Include interaction states when they distinguish the
|
|
35
|
+
directions. If rendering is unavailable, label the output as concepts and name
|
|
36
|
+
what remains unverified. Never claim an unseen design was visually checked.
|
|
37
|
+
|
|
38
|
+
Give each direction a stable ID and a short descriptive name. Present the directions
|
|
39
|
+
in recommendation order, strongest first. Mark the strongest choices
|
|
40
|
+
"(Recommended)" and explain why they fit the stated goal. Recommendations are
|
|
41
|
+
judgments; do not invent usability results, performance gains or scores.
|
|
42
|
+
|
|
43
|
+
Beside the previews, use a short comparison table with each direction's ID,
|
|
44
|
+
main difference, benefit and tradeoff. Keep IDs stable when rankings change.
|
|
45
|
+
Ask the user to select their top two and give feedback on each, including what
|
|
46
|
+
to retain and what to change. Follow the host's question format. Wait for the
|
|
47
|
+
answer before narrowing or generating the next round.
|
|
48
|
+
|
|
49
|
+
## One component
|
|
50
|
+
|
|
51
|
+
When the scope is a single component rather than a screen or flow, build three
|
|
52
|
+
variants by default. When the authorized prototype scope includes the page
|
|
53
|
+
where the component renders, put them behind a switcher there, so the user
|
|
54
|
+
compares them where the component actually lives; otherwise compare them
|
|
55
|
+
within the scope you have. Keep the switcher and variants out of production
|
|
56
|
+
code paths, and remove them once a variant is chosen.
|
|
57
|
+
|
|
58
|
+
Pick one design axis and give each variant a different position on it:
|
|
59
|
+
structure (grouping, order, what collapses), density (spacing, hit areas),
|
|
60
|
+
emphasis (where strong color and weight go), type (scale and weight contrast)
|
|
61
|
+
or voice (labels and amount of copy). Let secondary choices follow from that
|
|
62
|
+
position. Variants that differ on several axes at once cannot show which
|
|
63
|
+
change made the difference. Name each variant for its direction, not "Option
|
|
64
|
+
A". Before ranking, name the accessibility checks every variant must pass, at
|
|
65
|
+
least keyboard reach, visible focus, accessible names for controls, no
|
|
66
|
+
clipping at the narrowest supported width and no meaning carried by color
|
|
67
|
+
alone, plus `hr-better-accessibility`'s checks when it is available. Check
|
|
68
|
+
each variant against the same list and drop any direction that fails one.
|
|
69
|
+
|
|
70
|
+
Rank and refine the variants as described below.
|
|
71
|
+
|
|
72
|
+
## Refine the selected two
|
|
73
|
+
|
|
74
|
+
Record the chosen IDs and feedback in the task's durable design notes. Keep
|
|
75
|
+
eliminated directions there so later rounds do not revive rejected ideas by
|
|
76
|
+
accident. If the user chooses one as final, move to final selection below.
|
|
77
|
+
|
|
78
|
+
By default, show four options again:
|
|
79
|
+
|
|
80
|
+
1. The first selected design, unchanged as a comparison.
|
|
81
|
+
2. The second selected design, unchanged as a comparison.
|
|
82
|
+
3. One variation of the first design responding to its feedback.
|
|
83
|
+
4. One variation of the second design responding to its feedback.
|
|
84
|
+
|
|
85
|
+
Give variations new IDs and name their parent IDs. Explain what changed and
|
|
86
|
+
which feedback it addresses. Keep the inherited strengths visible and the
|
|
87
|
+
variation distinct enough to assess. Rerank the round against the goal and
|
|
88
|
+
latest feedback, mark recommended choices, and ask for the next top two with
|
|
89
|
+
feedback on each.
|
|
90
|
+
|
|
91
|
+
Repeat this round only after a new selection. Do not add new unrelated
|
|
92
|
+
concepts unless the user asks to reopen exploration. If feedback leaves no
|
|
93
|
+
meaningful variation to test, offer final selection or ask which unresolved
|
|
94
|
+
tradeoff needs another round instead of inventing cosmetic differences.
|
|
95
|
+
|
|
96
|
+
## Final selection
|
|
97
|
+
|
|
98
|
+
An explicit final choice ends exploration; no minimum round count is required.
|
|
99
|
+
Record the chosen ID, accepted refinements, rejected directions and remaining
|
|
100
|
+
uncertainties. Summarize the final design's layout, interactions and relevant
|
|
101
|
+
responsive states so implementation can follow it.
|
|
102
|
+
|
|
103
|
+
Choosing two for refinement authorizes that comparison, not promotion of a
|
|
104
|
+
winner. Apply the final design within existing implementation authorization;
|
|
105
|
+
when implementation or landing has not been authorized, offer that next step.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "HR: Design exploration"
|
|
3
|
+
short_description: "Compare design directions or component variants and refine"
|
|
4
|
+
default_prompt: "Use $hr-design-exploration to show four ranked visual directions, or three variants on one design axis for a single component, and refine my top two toward a final design."
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Source notices
|
|
2
|
+
|
|
3
|
+
This notice accompanies the hr-diagnosing-bugs bundle when copied on its own.
|
|
4
|
+
|
|
5
|
+
## mattpocock/skills
|
|
6
|
+
|
|
7
|
+
Source: https://github.com/mattpocock/skills (compared at revision `d81f3a1`)
|
|
8
|
+
|
|
9
|
+
- `skills/hr-diagnosing-bugs/`: written for this repository after
|
|
10
|
+
`skills/engineering/diagnosing-bugs/`, which it shares a purpose with.
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Matt Pocock
|
|
13
|
+
|
|
14
|
+
## cursor/plugins (pstack)
|
|
15
|
+
|
|
16
|
+
Source: https://github.com/cursor/plugins (compared at revision `e43c7ee`)
|
|
17
|
+
|
|
18
|
+
- `skills/hr-diagnosing-bugs/SKILL.md`: § Question the premise is adapted from
|
|
19
|
+
`pstack/skills/principle-attack-the-premise/`.
|
|
20
|
+
|
|
21
|
+
Copyright (c) 2026 Lauren Tan
|
|
22
|
+
|
|
23
|
+
## house-rules and MIT permission notice
|
|
24
|
+
|
|
25
|
+
MIT License
|
|
26
|
+
|
|
27
|
+
Copyright (c) 2026 Aaron Queen
|
|
28
|
+
|
|
29
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
30
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
31
|
+
in the Software without restriction, including without limitation the rights
|
|
32
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
33
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
34
|
+
furnished to do so, subject to the following conditions:
|
|
35
|
+
|
|
36
|
+
The above copyright notice and this permission notice shall be included in all
|
|
37
|
+
copies or substantial portions of the Software.
|
|
38
|
+
|
|
39
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
40
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
41
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
42
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
43
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
44
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
45
|
+
SOFTWARE.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hr-diagnosing-bugs
|
|
3
|
+
description: Investigate unknown-cause or intermittent bugs and performance regressions systematically. Evident fixes only on explicit diagnosis requests; exclude change reviews.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Diagnosing bugs
|
|
7
|
+
|
|
8
|
+
When filing an upstream bug, follow [Reporting a bug](references/reporting.md)
|
|
9
|
+
for reduction, submission and fix verification.
|
|
10
|
+
|
|
11
|
+
Follow project guidance for source paths, domain safeguards, tests and deployment.
|
|
12
|
+
Read relevant domain documents when they help explain the affected behavior.
|
|
13
|
+
Choose the next probe from the evidence; these techniques are not mandatory phases.
|
|
14
|
+
|
|
15
|
+
## Choose a model when needed
|
|
16
|
+
|
|
17
|
+
If the project names a benchmark-backed order for bug-finding models and
|
|
18
|
+
efforts, use it. Primary, secondary and tertiary choices can change with benchmark
|
|
19
|
+
results; read the current selection rather than carrying names from an old run.
|
|
20
|
+
If the primary is unavailable through quota, outage or an unsupported route,
|
|
21
|
+
use the next available eligible choice within authorized billing limits only
|
|
22
|
+
when changing provider, model or effort is authorized. When the low-quota
|
|
23
|
+
handoff rule applies, use the `hr-handoff` skill and stop, even if a model change
|
|
24
|
+
was authorized. Preserve review independence and record the model, effort and fallback
|
|
25
|
+
reason.
|
|
26
|
+
If no eligible model is available, report the blocker.
|
|
27
|
+
|
|
28
|
+
## Establish the symptom
|
|
29
|
+
|
|
30
|
+
Identify expected and observed behavior and seek a repeatable signal for the
|
|
31
|
+
reported failure. Source inspection and initial hypotheses can help construct it.
|
|
32
|
+
Prefer an existing test, command or captured input before building a harness.
|
|
33
|
+
Minimize the scenario when doing so helps distinguish causes or create a useful
|
|
34
|
+
regression test; an exhaustively minimal reproduction is not a prerequisite.
|
|
35
|
+
|
|
36
|
+
For intermittent failures, record attempts and failures under comparable
|
|
37
|
+
conditions. Increase the reproduction rate when practical within host load and
|
|
38
|
+
environment safeguards; do not impose a fixed retry count or success threshold.
|
|
39
|
+
For performance regressions, establish a measured baseline before changing code.
|
|
40
|
+
|
|
41
|
+
If reproduction is unavailable, continue useful source and artifact analysis,
|
|
42
|
+
label hypotheses as unverified, and report what would confirm them. Ask for
|
|
43
|
+
missing access or evidence only when it blocks further progress. Production
|
|
44
|
+
instrumentation still requires the applicable authorization.
|
|
45
|
+
|
|
46
|
+
## Distinguish causes
|
|
47
|
+
|
|
48
|
+
State a falsifiable prediction for the likely cause and test it. Consider
|
|
49
|
+
alternatives when evidence is ambiguous or a probe fails; there is no hypothesis
|
|
50
|
+
quota. Use targeted inspection, a debugger, logs, replay, bisection or differential
|
|
51
|
+
testing according to the uncertainty each resolves. Keep probes attributable by
|
|
52
|
+
changing one relevant variable at a time where practical.
|
|
53
|
+
|
|
54
|
+
When the cause depends on event order between actors, control the relevant
|
|
55
|
+
boundaries in an implementation test. Pause a response or write, interrupt the
|
|
56
|
+
process, then resume or restart it and assert the visible result. Use barriers
|
|
57
|
+
or explicit signals instead of sleeps to force the failing order. When the
|
|
58
|
+
failing order is unknown, the `hr-ordering-tests` skill enumerates the orderings
|
|
59
|
+
through the real code and names the sequence that breaks.
|
|
60
|
+
|
|
61
|
+
Keep secrets out of commands and shared artifacts; use environment variables
|
|
62
|
+
for credentials and redact captured headers or logs before displaying them.
|
|
63
|
+
Tag temporary instrumentation so it can be found and removed. When a human must
|
|
64
|
+
perform a reproduction step, give clear steps and the expected observation.
|
|
65
|
+
|
|
66
|
+
## Bound the loop
|
|
67
|
+
|
|
68
|
+
When retrying a probe or fix, cap attempts per hypothesis, stop on
|
|
69
|
+
no-progress (repeated identical calls, oscillation, unchanged error class),
|
|
70
|
+
and enforce time/token/cost ceilings outside the agent so a stuck loop
|
|
71
|
+
terminates instead of retrying.
|
|
72
|
+
|
|
73
|
+
## Question the premise
|
|
74
|
+
|
|
75
|
+
When two fixes that rest on the same assumption have failed the same check,
|
|
76
|
+
stop fixing and test the assumption. Write it down as the one sentence every
|
|
77
|
+
failed fix took for granted. Before a third fix, gather evidence that would
|
|
78
|
+
show the sentence false, such as a count per input, actor or run, and keep it
|
|
79
|
+
as a script that can be rerun. If the evidence contradicts the sentence, find
|
|
80
|
+
what made it false and fix that, instead of compensating for it on every run.
|
|
81
|
+
If the evidence supports the sentence, keep it as a record and look for the
|
|
82
|
+
cause elsewhere.
|
|
83
|
+
|
|
84
|
+
## Fix and verify
|
|
85
|
+
|
|
86
|
+
When the confirmed cause admits more than one viable fix, such as a targeted
|
|
87
|
+
workaround versus a root-cause correction, present the fixes as an offer (the house rules' § Offers) with
|
|
88
|
+
rough relative effort before changing code. Mark the recommendation and name
|
|
89
|
+
the right fix when it differs, with the reason: scope, risk, blast radius or
|
|
90
|
+
existing debt. Skip this when the evidence supports a single obvious fix or
|
|
91
|
+
the user already prescribed the remedy.
|
|
92
|
+
|
|
93
|
+
Make the smallest fix supported by the evidence. Use a regression assertion that
|
|
94
|
+
exercises the actual failure when a suitable seam exists and the change warrants
|
|
95
|
+
it under project guidance. It must fail on the pre-fix code for the intended
|
|
96
|
+
reason and pass after the fix, as `hr-test-audit` requires. Test-first ordering is optional
|
|
97
|
+
unless requested or required by the project.
|
|
98
|
+
|
|
99
|
+
Recheck the original symptom, including the original scenario if a minimized
|
|
100
|
+
case was used. For intermittent or performance issues, compare measurements and
|
|
101
|
+
report their limits. If verification is blocked or coverage lacks a suitable
|
|
102
|
+
seam, state the gap rather than claiming the fix is proven or expanding the
|
|
103
|
+
architecture without authorization.
|
|
104
|
+
|
|
105
|
+
Remove temporary instrumentation and throwaway artifacts. Report the cause,
|
|
106
|
+
change, checks actually run and remaining uncertainty. Recommend preventive work
|
|
107
|
+
only when the evidence supports a concrete benefit; follow project completion
|
|
108
|
+
and scope boundaries.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Reporting a bug
|
|
2
|
+
|
|
3
|
+
Before filing, apply the submission search in your loaded agent guidance's "Repository work" section.
|
|
4
|
+
If that section is unavailable, locate the local house-rules checkout and read
|
|
5
|
+
`rules/core.md` there. Report an unavailable local source before submitting.
|
|
6
|
+
Inspect labels, linked changes and timeline actions as well as comments.
|
|
7
|
+
For the same problem and scope, add new evidence to a matching open issue.
|
|
8
|
+
When a closed report still reproduces and remains materially unchanged,
|
|
9
|
+
explain the failed fix or changed conditions and request reopening. If reopening
|
|
10
|
+
is unavailable, file one linked follow-up. For material changes, use the
|
|
11
|
+
replacement workflow below.
|
|
12
|
+
|
|
13
|
+
Reduce the failure to the smallest self-contained reproduction you can verify.
|
|
14
|
+
Remove unrelated code, dependencies, data and setup. Keep reducing until each
|
|
15
|
+
remaining part is needed to reproduce the failure. For a library failure,
|
|
16
|
+
trace the failing path and isolate its underlying runtime API or language
|
|
17
|
+
operation. Use source inspection, profiling or controlled substitutions to
|
|
18
|
+
choose the next reduction; a slow dependency does not establish its cause.
|
|
19
|
+
|
|
20
|
+
Verify both the final reduction and the original scenario with exact commands
|
|
21
|
+
and pinned versions. Preserve the inputs, output checks and relevant allocation,
|
|
22
|
+
retention, concurrency or lifecycle behavior. A similar standalone failure is
|
|
23
|
+
a contributor observation until evidence connects it to the original symptom.
|
|
24
|
+
For performance or memory bugs, compare equivalent work under the applicable
|
|
25
|
+
benchmark protocol. State units, repetitions, variability and measured controls;
|
|
26
|
+
put the focused case before a larger comparison matrix.
|
|
27
|
+
|
|
28
|
+
Include a cause-and-reduction note in the report: the isolated operation,
|
|
29
|
+
evidence connecting it to the original failure, and remaining uncertainty.
|
|
30
|
+
Test the proposed cause by changing or removing the suspected factor while
|
|
31
|
+
preserving the other relevant conditions. Distinguish a reproduced operation,
|
|
32
|
+
a supported causal explanation and a confirmed internal defect. Do not infer
|
|
33
|
+
an engine defect merely because one runtime is slower on a library workload.
|
|
34
|
+
|
|
35
|
+
Lead with one symptom, the reproduction, expected and actual text results,
|
|
36
|
+
and the versions and environment needed to reproduce it. Check the current
|
|
37
|
+
stable release; identify development builds separately when tested. A verified
|
|
38
|
+
small reproduction can be reported while its internal cause remains unknown.
|
|
39
|
+
|
|
40
|
+
Add an image or chart to the report only as the "Visuals in issues, discussions
|
|
41
|
+
and comments" section of your loaded guidance describes; locate it in `rules/core.md`
|
|
42
|
+
when it is not loaded.
|
|
43
|
+
|
|
44
|
+
Show direct reproduction commands. Omit incidental scheduling, resource-control
|
|
45
|
+
and observer wrappers from issue and pull request examples. When a control is
|
|
46
|
+
required to reproduce the defect, include it and explain why. Keep exact executed
|
|
47
|
+
commands in measurement records; disclose material conditions beside performance
|
|
48
|
+
results without presenting local controls as prerequisites or changing historical
|
|
49
|
+
conditions. This reporting choice is checked by the author, not a syntax gate.
|
|
50
|
+
|
|
51
|
+
When reduction is blocked, record the attempted isolations and why the remaining
|
|
52
|
+
parts are necessary before asking whether to submit the broader case.
|
|
53
|
+
|
|
54
|
+
Read the repository's contribution guidance and matching issue template,
|
|
55
|
+
including organization defaults. Complete required fields and checklists.
|
|
56
|
+
Submit a YAML issue form (`.github/ISSUE_TEMPLATE/*.yml`) through the form
|
|
57
|
+
itself. `gh issue create` cannot submit one, so the form's labels, dropdowns
|
|
58
|
+
and checklist are lost, and copied headings alone do not preserve form
|
|
59
|
+
metadata. When the host has a browser signed in to the user's GitHub account,
|
|
60
|
+
open `https://github.com/<owner>/<repo>/issues/new?template=<file>.yml`, fill
|
|
61
|
+
every field and submit it there. Use the CLI only when the repository has no
|
|
62
|
+
issue form or only a Markdown template. Verify the published body and labels.
|
|
63
|
+
With no signed-in browser, prepare the report and ask for access or user
|
|
64
|
+
submission; do not fall back to `gh issue create` and drop the form's labels.
|
|
65
|
+
|
|
66
|
+
Every issue offers the pull request, whatever the repository's triage timing.
|
|
67
|
+
Waiting for a maintainer's verdict decides when you open the pull request, not
|
|
68
|
+
whether the issue says one is available. State in the issue's fix or workaround
|
|
69
|
+
field (or its closing lines, when the form has none) what exists and offer the
|
|
70
|
+
pull request: "None applied. I can open a pull request for this once triage
|
|
71
|
+
confirms the direction. <branch exists / not written yet>; <the approach or
|
|
72
|
+
options I would measure>." When a branch or pull request already exists, link it
|
|
73
|
+
instead.
|
|
74
|
+
|
|
75
|
+
Before showing a draft to the user, run
|
|
76
|
+
`node scripts/check-pr-offer.mjs <draft.md>` from this skill; it fails when that
|
|
77
|
+
text does not offer a pull request or link a pull request or branch. It is a
|
|
78
|
+
text match: it skips a sentence that puts a negation before "pull request" but
|
|
79
|
+
cannot judge meaning, so confirm the offer is genuine yourself. Read the offer back from the
|
|
80
|
+
form's fields before submitting.
|
|
81
|
+
|
|
82
|
+
When an issue needs major or material changes, replace it with a new issue
|
|
83
|
+
in any repository. Compare the proposed revision with the published report.
|
|
84
|
+
A revision is major or material if it changes the reported problem, scope,
|
|
85
|
+
reproduction mechanism or main conclusion. Carry forward relevant evidence and unresolved
|
|
86
|
+
questions, and link the old and new reports both ways. Submit and verify the
|
|
87
|
+
replacement before closing the old report as superseded, not fixed. Routine
|
|
88
|
+
corrections and evidence that leave the report materially unchanged stay in place.
|
|
89
|
+
|
|
90
|
+
Keep one active report per problem after replacement. Follow up with new
|
|
91
|
+
evidence or a specific unanswered question. An absent bot comment is not
|
|
92
|
+
evidence that nothing happened. Do not duplicate a report or close and reopen it merely to seek
|
|
93
|
+
priority. Small examples help investigation; they do not guarantee action or a fix deadline.
|
|
94
|
+
|
|
95
|
+
When a fix build is available, test the same reproduction and report the
|
|
96
|
+
revision and before/after result. Distinguish triage, an open fix, a merged fix
|
|
97
|
+
and a released fix. Verify the affected behavior before calling it resolved.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Fails when an issue draft neither offers a pull request nor links one.
|
|
3
|
+
// usage: check-pr-offer.mjs <draft.md> (or the draft on stdin)
|
|
4
|
+
// The text checked is the "Fix applied or workaround" field when the draft has one, else the
|
|
5
|
+
// draft's last lines. Run it before showing a draft to the user and again on the filed body.
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
|
|
8
|
+
const TAIL_LINES = 8;
|
|
9
|
+
const FIELD = /^(?:#{1,6}\s*|\*\*)?fix applied or workaround\b/i;
|
|
10
|
+
const HEADING = /^#{1,6}\s/;
|
|
11
|
+
const OFFER = /pull request|github\.com\/[^\s/]+\/[^\s/]+\/(?:pull\/\d+|tree\/\S+)/i;
|
|
12
|
+
// A sentence that denies the offer ("I cannot open a pull request") does not count.
|
|
13
|
+
const DENIAL = /\b(?:cannot|can't|can not|won't|will not|unable|never|no|not)\b[^.]*pull request/i;
|
|
14
|
+
|
|
15
|
+
// The field's text: from its heading or label to the next heading, or null when the draft has none.
|
|
16
|
+
export function offerText(draft) {
|
|
17
|
+
const lines = draft.split("\n");
|
|
18
|
+
const start = lines.findIndex((l) => FIELD.test(l.trim()));
|
|
19
|
+
if (start >= 0) {
|
|
20
|
+
const end = lines.findIndex((l, i) => i > start && HEADING.test(l));
|
|
21
|
+
return lines.slice(start, end < 0 ? undefined : end).join("\n");
|
|
22
|
+
}
|
|
23
|
+
return lines
|
|
24
|
+
.filter((l) => l.trim())
|
|
25
|
+
.slice(-TAIL_LINES)
|
|
26
|
+
.join("\n");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const offersPullRequest = (draft) =>
|
|
30
|
+
OFFER.test(
|
|
31
|
+
offerText(draft)
|
|
32
|
+
.split(/(?<=[.!?])\s+|\n/)
|
|
33
|
+
.filter((sentence) => !DENIAL.test(sentence))
|
|
34
|
+
.join("\n"),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (import.meta.main ?? import.meta.url === `file://${process.argv[1]}`) {
|
|
38
|
+
const draft = readFileSync(process.argv[2] ?? 0, "utf8");
|
|
39
|
+
if (offersPullRequest(draft)) {
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
console.error(
|
|
43
|
+
'FAIL: the "Fix applied or workaround" text (or the draft\'s closing lines) neither says "pull request" nor links one.\n' +
|
|
44
|
+
'Add the offer: "None applied. I can open a pull request for this once triage confirms the direction. <branch exists / not written yet>; <the approach I would measure>." or link the existing branch or pull request.',
|
|
45
|
+
);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|