@jesdi/skills 0.0.29 → 0.0.31
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/README.md +61 -13
- package/package.json +9 -1
- package/skills/implement-spec/ARCHITECTURE.md +113 -0
- package/skills/implement-spec/README.md +214 -0
- package/skills/implement-spec/SKILL.md +18 -70
- package/skills/implement-spec/driver.py +580 -0
- package/skills/implement-spec/driver_agents.py +145 -0
- package/skills/implement-spec/driver_answers.py +79 -0
- package/skills/implement-spec/driver_decisions.py +152 -0
- package/skills/implement-spec/driver_final.py +505 -0
- package/skills/implement-spec/driver_fixloop.py +170 -0
- package/skills/implement-spec/driver_gate.py +47 -0
- package/skills/implement-spec/driver_graph.py +42 -0
- package/skills/implement-spec/driver_merge.py +105 -0
- package/skills/implement-spec/driver_report.py +115 -0
- package/skills/implement-spec/driver_review.py +126 -0
- package/skills/implement-spec/driver_review_page.py +51 -0
- package/skills/implement-spec/driver_run.py +262 -0
- package/skills/implement-spec/driver_slots.py +64 -0
- package/skills/implement-spec/driver_state.py +105 -0
- package/skills/implement-spec/driver_summary.py +40 -0
- package/skills/implement-spec/driver_tickets.py +132 -0
- package/skills/implement-spec/driver_tidy.py +57 -0
- package/skills/implement-spec/models.json +10 -0
- package/skills/implement-spec/prompts/conflict.md +32 -0
- package/skills/implement-spec/prompts/correction.md +4 -0
- package/skills/implement-spec/prompts/correctness.md +34 -0
- package/skills/implement-spec/prompts/final-fixer.md +36 -0
- package/skills/implement-spec/prompts/final-reviewer.md +36 -0
- package/skills/implement-spec/prompts/final-scoped.md +1 -0
- package/skills/implement-spec/prompts/fixer.md +35 -0
- package/skills/implement-spec/prompts/implementer.md +33 -0
- package/skills/implement-spec/prompts/interrupted.md +1 -0
- package/skills/implement-spec/prompts/moved.md +2 -0
- package/skills/implement-spec/prompts/overruled.md +5 -0
- package/skills/implement-spec/prompts/pr-body.md +19 -0
- package/skills/implement-spec/prompts/rebase-conflict.md +33 -0
- package/skills/implement-spec/prompts/rereview.md +3 -0
- package/skills/implement-spec/prompts/rerun.md +2 -0
- package/skills/implement-spec/prompts/reviewer.md +34 -0
- package/skills/implement-spec/prompts/stands.md +2 -0
- package/skills/implement-spec/prompts/test-writer.md +34 -0
- package/skills/implement-spec/prompts/timeout-restored.md +2 -0
- package/skills/implement-spec/prompts/timeout-shared.md +2 -0
- package/skills/implement-spec/prompts/timeout.md +2 -0
- package/skills/implement-spec/run.sh +101 -0
- package/skills/implement-spec/tests/conftest.py +38 -0
- package/skills/implement-spec/tests/test_agents.py +358 -0
- package/skills/implement-spec/tests/test_amendments.py +117 -0
- package/skills/implement-spec/tests/test_cli.py +220 -0
- package/skills/implement-spec/tests/test_decisions.py +434 -0
- package/skills/implement-spec/tests/test_driver.py +767 -0
- package/skills/implement-spec/tests/test_final.py +442 -0
- package/skills/implement-spec/tests/test_fixloop.py +523 -0
- package/skills/implement-spec/tests/test_graph.py +32 -0
- package/skills/implement-spec/tests/test_landing.py +355 -0
- package/skills/implement-spec/tests/test_merge.py +144 -0
- package/skills/implement-spec/tests/test_models.py +47 -0
- package/skills/implement-spec/tests/test_report.py +162 -0
- package/skills/implement-spec/tests/test_review.py +338 -0
- package/skills/implement-spec/tests/test_review_page.py +67 -0
- package/skills/implement-spec/tests/test_slots.py +32 -0
- package/skills/implement-spec/tests/test_state.py +68 -0
- package/skills/implement-spec/tests/test_stops.py +272 -0
- package/skills/implement-spec/tests/test_summary.py +28 -0
- package/skills/implement-spec/tests/test_tickets.py +72 -0
- package/skills/implement-spec/tests/test_tidy.py +582 -0
- package/skills/implement-spec/tests/test_walk.py +457 -0
- package/skills/review-page/SKILL.md +70 -0
- package/skills/review-page/schema.md +59 -0
- package/skills/review-page/template.html +232 -0
- package/skills/to-tickets/SKILL.md +19 -2
- package/skills-manifest.json +11 -5
- package/skills/implement-spec/history.md +0 -52
|
@@ -0,0 +1,232 @@
|
|
|
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
|
+
<meta name="agent-ops-review" content="1">
|
|
7
|
+
<title>Review</title>
|
|
8
|
+
<style>
|
|
9
|
+
/* Layout: one column, phone first; the console's own token system so the page
|
|
10
|
+
reads as part of the console, not as a foreign document. */
|
|
11
|
+
:root {
|
|
12
|
+
--surface: #f5f7fa; --raised: #ffffff; --ink: #1e293b; --muted: #5b6577;
|
|
13
|
+
--border: #dce1e8; --attention: #fbf6ec;
|
|
14
|
+
--waiting-bg: #fef3c7; --waiting-fg: #92400e;
|
|
15
|
+
--running-bg: #dcfce7; --running-fg: #166534;
|
|
16
|
+
--parked-bg: #ede9fe; --parked-fg: #5b21b6;
|
|
17
|
+
--accent: #1e40af; --accent-bg: #dbeafe;
|
|
18
|
+
--sans: "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif;
|
|
19
|
+
--mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
20
|
+
}
|
|
21
|
+
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {
|
|
22
|
+
--surface: #0f141a; --raised: #181e27; --ink: #e4e8ee; --muted: #98a2b1;
|
|
23
|
+
--border: #2b3340; --attention: #1f1b15;
|
|
24
|
+
--waiting-bg: #372812; --waiting-fg: #fcd34d;
|
|
25
|
+
--running-bg: #10301e; --running-fg: #86efac;
|
|
26
|
+
--parked-bg: #291f45; --parked-fg: #c4b5fd;
|
|
27
|
+
--accent: #93c5fd; --accent-bg: #1e293b; color-scheme: dark } }
|
|
28
|
+
:root[data-theme="dark"] {
|
|
29
|
+
--surface: #0f141a; --raised: #181e27; --ink: #e4e8ee; --muted: #98a2b1;
|
|
30
|
+
--border: #2b3340; --attention: #1f1b15;
|
|
31
|
+
--waiting-bg: #372812; --waiting-fg: #fcd34d;
|
|
32
|
+
--running-bg: #10301e; --running-fg: #86efac;
|
|
33
|
+
--parked-bg: #291f45; --parked-fg: #c4b5fd;
|
|
34
|
+
--accent: #93c5fd; --accent-bg: #1e293b; color-scheme: dark }
|
|
35
|
+
|
|
36
|
+
* { box-sizing: border-box }
|
|
37
|
+
body { margin: 0; background: var(--surface); color: var(--ink); font: 14px/1.5 var(--sans) }
|
|
38
|
+
main { max-width: 680px; margin: 0 auto; padding: 16px 16px 112px }
|
|
39
|
+
h1 { font-size: 18px; font-weight: 600; margin: 0; text-wrap: balance; line-height: 1.3 }
|
|
40
|
+
h2 { font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); margin: 0 }
|
|
41
|
+
section { display: grid; gap: 10px; margin-top: 24px }
|
|
42
|
+
p { margin: 0 }
|
|
43
|
+
code { font: 12px var(--mono); overflow-wrap: anywhere }
|
|
44
|
+
.eyebrow { font: 500 12px var(--mono); color: var(--muted); margin-bottom: 6px; overflow-wrap: anywhere }
|
|
45
|
+
.lede { color: var(--muted); margin-top: 6px }
|
|
46
|
+
.chip { display: inline-block; border-radius: 4px; padding: 0 6px; font-size: 11px; font-weight: 500; white-space: nowrap }
|
|
47
|
+
.chip.waiting { background: var(--waiting-bg); color: var(--waiting-fg) }
|
|
48
|
+
.chip.rec { background: var(--running-bg); color: var(--running-fg) }
|
|
49
|
+
.chip.parked { background: var(--parked-bg); color: var(--parked-fg) }
|
|
50
|
+
|
|
51
|
+
/* Tickets: a plain list, numbered because the order is the build order. */
|
|
52
|
+
ol.tickets { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px }
|
|
53
|
+
ol.tickets li { display: grid; grid-template-columns: 28px 1fr; gap: 8px; align-items: baseline }
|
|
54
|
+
ol.tickets .n { font: 500 12px var(--mono); color: var(--muted); font-variant-numeric: tabular-nums }
|
|
55
|
+
ol.tickets .by { color: var(--muted); font-size: 12px }
|
|
56
|
+
|
|
57
|
+
/* Questions: the one boxed element, because it takes input. */
|
|
58
|
+
.q { background: var(--raised); border: 1px solid var(--border); border-radius: 6px; padding: 12px; overflow-wrap: anywhere }
|
|
59
|
+
.q.answered { border-color: color-mix(in srgb, var(--running-fg) 40%, var(--border)) }
|
|
60
|
+
.q header { display: flex; justify-content: space-between; gap: 8px; align-items: baseline }
|
|
61
|
+
.q h3 { font-size: 14px; font-weight: 600; margin: 0; text-wrap: balance }
|
|
62
|
+
.q .why { color: var(--muted); margin-top: 4px }
|
|
63
|
+
.opts { display: grid; gap: 6px; margin-top: 10px }
|
|
64
|
+
.opt { display: grid; grid-template-columns: 18px 1fr; gap: 10px; align-items: start;
|
|
65
|
+
border: 1px solid var(--border); border-radius: 6px; padding: 10px; cursor: pointer; min-height: 44px }
|
|
66
|
+
.opt input { margin: 3px 0 0; width: 16px; height: 16px; accent-color: var(--accent) }
|
|
67
|
+
.opt:has(input:checked) { border-color: var(--accent); background: var(--accent-bg) }
|
|
68
|
+
.opt:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px }
|
|
69
|
+
.opt .t { font-weight: 500 }
|
|
70
|
+
.opt .d { color: var(--muted); font-size: 13px }
|
|
71
|
+
.q textarea { width: 100%; margin-top: 10px; min-height: 44px; border: 1px solid var(--border); border-radius: 6px;
|
|
72
|
+
padding: 8px 10px; font: 13px/1.5 var(--sans); background: var(--surface); color: var(--ink); resize: vertical }
|
|
73
|
+
.q textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px }
|
|
74
|
+
|
|
75
|
+
/* Corrections: before / after pairs. */
|
|
76
|
+
.corr { display: grid; gap: 4px; padding-left: 10px; border-left: 2px solid var(--border) }
|
|
77
|
+
.corr .was { color: var(--muted); text-decoration: line-through }
|
|
78
|
+
|
|
79
|
+
/* Track selector: a row of pills. */
|
|
80
|
+
.tracks { display: flex; flex-wrap: wrap; gap: 6px }
|
|
81
|
+
.tracks label { border: 1px solid var(--border); border-radius: 999px; padding: 6px 12px; min-height: 36px;
|
|
82
|
+
display: inline-flex; align-items: center; cursor: pointer; background: var(--raised) }
|
|
83
|
+
.tracks label:has(input:checked) { border-color: var(--accent); background: var(--accent-bg); color: var(--accent); font-weight: 500 }
|
|
84
|
+
.tracks label:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px }
|
|
85
|
+
.tracks input { position: absolute; opacity: 0; width: 0; height: 0 }
|
|
86
|
+
|
|
87
|
+
/* State bar: fixed to the bottom. The console owns the buttons: a page never submits. */
|
|
88
|
+
.bar { position: fixed; left: 0; right: 0; bottom: 0; background: var(--raised); border-top: 1px solid var(--border);
|
|
89
|
+
padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px)) }
|
|
90
|
+
.bar .in { max-width: 680px; margin: 0 auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap }
|
|
91
|
+
.bar .state { flex: 1 1 100%; font-size: 12px; color: var(--muted); min-width: 0 }
|
|
92
|
+
.bar .state.saved { color: var(--running-fg) }
|
|
93
|
+
|
|
94
|
+
@media (prefers-reduced-motion: no-preference) { .opt, .tracks label { transition: background .12s, border-color .12s } }
|
|
95
|
+
|
|
96
|
+
/* Questionnaire mode: questions only. */
|
|
97
|
+
body[data-mode="questionnaire"] section[data-slot="tickets"],
|
|
98
|
+
body[data-mode="questionnaire"] section[data-slot="corrections"],
|
|
99
|
+
body[data-mode="questionnaire"] section[data-slot="track"] { display: none }
|
|
100
|
+
</style>
|
|
101
|
+
</head>
|
|
102
|
+
<body data-mode="plan">
|
|
103
|
+
<main>
|
|
104
|
+
<!-- slot: header -->
|
|
105
|
+
<div class="eyebrow">plan review · owner/repo #123 · branch task/123-example</div>
|
|
106
|
+
<h1>Title of the plan</h1>
|
|
107
|
+
<p class="lede">2 tickets · 1 open question · 1 correction. Pick an option under each question, then send.</p>
|
|
108
|
+
<!-- /slot -->
|
|
109
|
+
|
|
110
|
+
<section data-slot="tickets">
|
|
111
|
+
<!-- slot: tickets -->
|
|
112
|
+
<h2>Tickets</h2>
|
|
113
|
+
<ol class="tickets">
|
|
114
|
+
<li><span class="n">01</span><span>First ticket title <span class="by">· seam: module.py</span></span></li>
|
|
115
|
+
<li><span class="n">02</span><span>Second ticket title <span class="by">· blocked by 01 · seam: other.py</span></span></li>
|
|
116
|
+
</ol>
|
|
117
|
+
<!-- /slot -->
|
|
118
|
+
</section>
|
|
119
|
+
|
|
120
|
+
<section data-slot="questions">
|
|
121
|
+
<!-- slot: questions -->
|
|
122
|
+
<h2>Open questions</h2>
|
|
123
|
+
<div class="q" data-q="format">
|
|
124
|
+
<header><h3>Which format does the export use?</h3><span class="chip waiting">needs you</span></header>
|
|
125
|
+
<p class="why">One sentence on why the answer matters.</p>
|
|
126
|
+
<div class="opts">
|
|
127
|
+
<label class="opt"><input type="radio" name="format" value="a"><span><span class="t">Option A <span class="chip rec">recommended</span></span><br><span class="d">What A costs and gives.</span></span></label>
|
|
128
|
+
<label class="opt"><input type="radio" name="format" value="b"><span><span class="t">Option B</span><br><span class="d">What B costs and gives.</span></span></label>
|
|
129
|
+
</div>
|
|
130
|
+
<textarea id="note-format" placeholder="Note (optional)"></textarea>
|
|
131
|
+
</div>
|
|
132
|
+
<!-- /slot -->
|
|
133
|
+
</section>
|
|
134
|
+
|
|
135
|
+
<section data-slot="corrections">
|
|
136
|
+
<!-- slot: corrections -->
|
|
137
|
+
<h2>Corrections</h2>
|
|
138
|
+
<div class="corr">
|
|
139
|
+
<p class="was">The old statement.</p>
|
|
140
|
+
<p>The corrected statement.</p>
|
|
141
|
+
<p class="why" style="color:var(--muted)">Why: the reason.</p>
|
|
142
|
+
</div>
|
|
143
|
+
<!-- /slot -->
|
|
144
|
+
</section>
|
|
145
|
+
|
|
146
|
+
<section data-slot="track">
|
|
147
|
+
<!-- slot: track -->
|
|
148
|
+
<h2>Track</h2>
|
|
149
|
+
<p class="why" style="color:var(--muted)">The plan session proposed <strong>standard</strong>. Change it only when needed.</p>
|
|
150
|
+
<div class="tracks" role="radiogroup" aria-label="track">
|
|
151
|
+
<label><input type="radio" name="track" value="trivial">trivial</label>
|
|
152
|
+
<label><input type="radio" name="track" value="standard" checked>standard</label>
|
|
153
|
+
<label><input type="radio" name="track" value="security">security</label>
|
|
154
|
+
</div>
|
|
155
|
+
<!-- /slot -->
|
|
156
|
+
</section>
|
|
157
|
+
</main>
|
|
158
|
+
|
|
159
|
+
<div class="bar">
|
|
160
|
+
<div class="in">
|
|
161
|
+
<p class="state" id="state">0 of 0 questions answered</p>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<script>
|
|
166
|
+
// Fixed part of the template: collect, post, restore. The session never edits this.
|
|
167
|
+
const V = 1;
|
|
168
|
+
const state = document.querySelector('.bar #state'); // lives in the bar, never in a slot
|
|
169
|
+
const embedded = window.parent !== window;
|
|
170
|
+
const questions = () => [...document.querySelectorAll('.q[data-q]')];
|
|
171
|
+
let restored = false;
|
|
172
|
+
|
|
173
|
+
function collect() {
|
|
174
|
+
const answers = {};
|
|
175
|
+
for (const el of questions()) {
|
|
176
|
+
const q = el.dataset.q;
|
|
177
|
+
const picked = [...document.getElementsByName(q)].find(i => i.checked);
|
|
178
|
+
if (picked) answers[q] = picked.value;
|
|
179
|
+
const note = document.getElementById('note-' + q);
|
|
180
|
+
if (note && note.value.trim()) answers[q + '.note'] = note.value.trim();
|
|
181
|
+
}
|
|
182
|
+
const track = document.querySelector('input[name="track"]:checked');
|
|
183
|
+
if (track) answers.track = track.value;
|
|
184
|
+
return answers;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function post() {
|
|
188
|
+
// In the console this is the only way out of the sandbox. Always a draft:
|
|
189
|
+
// the console's own buttons submit, so no page script can approve.
|
|
190
|
+
if (embedded) window.parent.postMessage({ type: 'answers', v: V, answers: collect(), submit: null }, '*');
|
|
191
|
+
paint();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function paint() {
|
|
195
|
+
let n = 0;
|
|
196
|
+
const all = questions();
|
|
197
|
+
for (const el of all) {
|
|
198
|
+
const done = [...document.getElementsByName(el.dataset.q)].some(i => i.checked);
|
|
199
|
+
el.classList.toggle('answered', done);
|
|
200
|
+
const chip = el.querySelector('header .chip.waiting, header .chip.rec');
|
|
201
|
+
if (chip) { chip.textContent = done ? 'answered' : 'needs you'; chip.className = done ? 'chip rec' : 'chip waiting'; }
|
|
202
|
+
if (done) n++;
|
|
203
|
+
}
|
|
204
|
+
state.textContent = `${n} of ${all.length} questions answered` + (restored ? ' · saved answers restored' : '');
|
|
205
|
+
state.classList.toggle('saved', restored);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function restore(answers) {
|
|
209
|
+
for (const [k, v] of Object.entries(answers || {})) {
|
|
210
|
+
if (k.endsWith('.note')) { const t = document.getElementById('note-' + k.slice(0, -5)); if (t) t.value = v; continue; }
|
|
211
|
+
const input = [...document.getElementsByName(k)].find(i => i.value === v);
|
|
212
|
+
if (input) input.checked = true;
|
|
213
|
+
}
|
|
214
|
+
paint();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
document.addEventListener('change', e => {
|
|
218
|
+
if (e.target.type === 'radio') post();
|
|
219
|
+
});
|
|
220
|
+
document.addEventListener('input', e => { if (e.target.tagName === 'TEXTAREA') post(); });
|
|
221
|
+
|
|
222
|
+
// From the console: saved answers, when the page reopens on any device.
|
|
223
|
+
window.addEventListener('message', e => {
|
|
224
|
+
const d = e.data;
|
|
225
|
+
if (e.source !== window.parent || !d || d.v !== V || d.type !== 'restore') return;
|
|
226
|
+
restored = Object.keys(d.answers || {}).length > 0; restore(d.answers);
|
|
227
|
+
});
|
|
228
|
+
if (embedded) window.parent.postMessage({ type: 'ready', v: V }, '*');
|
|
229
|
+
paint();
|
|
230
|
+
</script>
|
|
231
|
+
</body>
|
|
232
|
+
</html>
|
|
@@ -10,7 +10,8 @@ Changes: tickets always go to `.agent/tickets/<NN>-<slug>.md` (no tracker path);
|
|
|
10
10
|
numbering is contiguous from 01 in dependency order; acceptance criteria must state
|
|
11
11
|
observable behavior; every ticket names its **Seam** (the public interface its
|
|
12
12
|
acceptance tests hit) and what it **Touches** (files and functions, for
|
|
13
|
-
scheduling)
|
|
13
|
+
scheduling) and may carry optional **Risk** and **Suspicions** lines for
|
|
14
|
+
the review; trivial slices fold into a neighbour; tickets never carry the
|
|
14
15
|
implementation; the approval quiz is skipped when unattended; model invocation is
|
|
15
16
|
allowed.
|
|
16
17
|
-->
|
|
@@ -41,7 +42,7 @@ Break the work into **tracer bullet** tickets.
|
|
|
41
42
|
- A completed slice is demoable or verifiable on its own
|
|
42
43
|
- Each slice is sized to fit in a single fresh context window
|
|
43
44
|
- Any prefactoring should be done first
|
|
44
|
-
- No trivial tickets: when a slice's whole change is a small guard or fix (a few lines) and no other ticket is blocked by it, fold its acceptance criteria into the neighbouring ticket that touches the same behaviour. Every ticket costs a test-writer, implementer
|
|
45
|
+
- No trivial tickets: when a slice's whole change is a small guard or fix (a few lines) and no other ticket is blocked by it, fold its acceptance criteria into the neighbouring ticket that touches the same behaviour. Every ticket costs a test-writer, an implementer and a reviewer; a two-line guard doesn't earn three agents
|
|
45
46
|
|
|
46
47
|
</vertical-slice-rules>
|
|
47
48
|
|
|
@@ -93,6 +94,10 @@ Do NOT close or modify any parent issue.
|
|
|
93
94
|
|
|
94
95
|
**Touches:** the files, and the functions within them, this ticket expects to change.
|
|
95
96
|
|
|
97
|
+
**Risk:** optional. The shared state, persistence, concurrency, money or auth this ticket touches. Omit the line when there is none.
|
|
98
|
+
|
|
99
|
+
**Suspicions:** optional. What the reviewer should test first: a sibling caller, a key built from the old identity, a guard another ticket added.
|
|
100
|
+
|
|
96
101
|
- [ ] Acceptance criterion 1
|
|
97
102
|
- [ ] Acceptance criterion 2
|
|
98
103
|
|
|
@@ -116,6 +121,18 @@ The **Touches** line is a best guess, for scheduling: `implement-spec` never run
|
|
|
116
121
|
|
|
117
122
|
</touches-rule>
|
|
118
123
|
|
|
124
|
+
<risk-rule>
|
|
125
|
+
|
|
126
|
+
The optional **Risk** line names the shared state, persistence keys or identities, concurrency, money or auth the ticket touches, and turns on `implement-spec`'s correctness pass: a second, independent reviewer on another provider. The driver does not start when it has no CLI of another provider: the reviewer never does this pass. Any text on the line turns the pass on, so a ticket with no such risk has no **Risk** line, never `**Risk:** none`.
|
|
127
|
+
|
|
128
|
+
</risk-rule>
|
|
129
|
+
|
|
130
|
+
<suspicions-rule>
|
|
131
|
+
|
|
132
|
+
The optional **Suspicions** line is passed verbatim to `implement-spec`'s reviewer, which tests each one: named suspicions find regressions a generic review misses.
|
|
133
|
+
|
|
134
|
+
</suspicions-rule>
|
|
135
|
+
|
|
119
136
|
Never write the implementation into a ticket. `implement-spec`'s test-writer reads the ticket and must not know the solution, or its acceptance tests stop being independent of the code they judge. Describe behaviour, not the fix.
|
|
120
137
|
|
|
121
138
|
Outside the **Touches** line, avoid specific file paths or code snippets: they go stale fast. Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it and note briefly that it came from a prototype. Trim to the decision-rich parts, the shape of the decision, never the code that implements the ticket.
|
package/skills-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-14T03:34:13.674Z",
|
|
4
4
|
"skills": [
|
|
5
5
|
{
|
|
6
6
|
"name": "backlog",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
"name": "implement-spec",
|
|
49
|
-
"version": "0.1.
|
|
50
|
-
"hash": "sha256-
|
|
49
|
+
"version": "0.1.8",
|
|
50
|
+
"hash": "sha256-cafda530227caa971251cbe0d677f758630f96d6178f75a5e32b93417efe033e",
|
|
51
51
|
"description": "Implement a specification in code."
|
|
52
52
|
},
|
|
53
53
|
{
|
|
@@ -74,6 +74,12 @@
|
|
|
74
74
|
"hash": "sha256-70beaf1478820d66e1831d45739ce97ced50224b46c5003d887ea62c8438f251",
|
|
75
75
|
"description": "Review a branch before merge: first a gate (the repo's check command plus crap-gate), then three independent reviewers in parallel — spec (did we build what was asked, no more, no less), correctness via Codex (races, idempotency, money, time, authz, indexes, N+1, migrations, error paths, test quality) and structure (deep-quality-review). `--quick` runs only spec and correctness, shortened, for a live interview. Use when the user says \"/review-diff\", \"review this branch\", \"review this slice\", \"review before merge\", or before closing out a spec task."
|
|
76
76
|
},
|
|
77
|
+
{
|
|
78
|
+
"name": "review-page",
|
|
79
|
+
"version": "0.1.1",
|
|
80
|
+
"hash": "sha256-e8204e4c6f05e2721a20d9ac3f72b8ff84a2854647688bb9bf057312b53a59f4",
|
|
81
|
+
"description": "One interactive HTML page for a plan review or a questionnaire, built from a fixed template. Use when a pipeline session must deliver a plan review or a questionnaire as an interactive page the console shows."
|
|
82
|
+
},
|
|
77
83
|
{
|
|
78
84
|
"name": "to-openspec",
|
|
79
85
|
"version": "0.1.3",
|
|
@@ -88,8 +94,8 @@
|
|
|
88
94
|
},
|
|
89
95
|
{
|
|
90
96
|
"name": "to-tickets",
|
|
91
|
-
"version": "0.1.
|
|
92
|
-
"hash": "sha256-
|
|
97
|
+
"version": "0.1.5",
|
|
98
|
+
"hash": "sha256-58d4b24183ba3ff59a97de963ab0cd8bbac91d526941eeb7ec0a84274e918faf",
|
|
93
99
|
"description": "Break a spec, plan, or the current conversation into numbered tracer-bullet ticket files under .agent/tickets/, each declaring its blocking edges and acceptance criteria phrased as observable behavior. Use after a spec is approved and before implementation starts."
|
|
94
100
|
},
|
|
95
101
|
{
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# History by ticket
|
|
2
|
-
|
|
3
|
-
Tidy the unpublished integration branch into one coherent commit per ticket,
|
|
4
|
-
ordered so each ticket follows its dependencies. Each commit contains that
|
|
5
|
-
ticket's acceptance tests, implementation, and all review or integration fixes.
|
|
6
|
-
The reviewer's commit list should tell the story of the tickets, with the
|
|
7
|
-
final behavior at each step.
|
|
8
|
-
|
|
9
|
-
## Before rewriting
|
|
10
|
-
|
|
11
|
-
- Confirm all ticket worktrees and branches were cleaned up after their merges,
|
|
12
|
-
and that the integration worktree is clean.
|
|
13
|
-
- Confirm the branch has never been pushed. Once pushed, preserve its history
|
|
14
|
-
and add reviewed follow-up commits; rewriting a published branch requires
|
|
15
|
-
explicit user authorization.
|
|
16
|
-
- Record the current tip and `HEAD^{tree}` in the ledger as the recovery point.
|
|
17
|
-
Use the ticket reports and ledger to map every working commit and every fix
|
|
18
|
-
to its owning ticket before editing history.
|
|
19
|
-
|
|
20
|
-
## Group the changes
|
|
21
|
-
|
|
22
|
-
Use an interactive rebase or reconstruct the commits in an isolated worktree,
|
|
23
|
-
operating only on branch-owned commits after the base. Fold red-test commits,
|
|
24
|
-
implementation commits, and later fixes into their ticket commit. Flatten
|
|
25
|
-
branch-only merge commits while preserving their conflict-resolution changes.
|
|
26
|
-
Keep the test-writer's acceptance files unchanged from their locked versions.
|
|
27
|
-
|
|
28
|
-
A fix touching several tickets is split by ownership when the resulting
|
|
29
|
-
commits can stand alone in dependency order. If it cannot be split safely,
|
|
30
|
-
combine the affected tickets into one coherent commit, name them in the
|
|
31
|
-
message, and record the reason in the ledger. Every final change has a ticket
|
|
32
|
-
owner; an out-of-scope change needs a ruling before inclusion.
|
|
33
|
-
|
|
34
|
-
Use a commit subject that names the ticket's delivered behavior and put its
|
|
35
|
-
ticket number or file pointer in the body. Keep a map from the old working
|
|
36
|
-
commits to the final ticket commits in the ledger; ticket reports and locked
|
|
37
|
-
test SHAs still refer to the original history.
|
|
38
|
-
|
|
39
|
-
## Completion
|
|
40
|
-
|
|
41
|
-
The rewritten tip's tree must equal the saved tree: history cleanup changes
|
|
42
|
-
the presentation of the work, not its files. A mismatch must be resolved
|
|
43
|
-
before review. Inspect each final commit's diff against its ticket to confirm
|
|
44
|
-
the tests, implementation, and fixes stayed together, dependencies precede
|
|
45
|
-
their consumers, and no temporary red-test or fix-only commits remain.
|
|
46
|
-
|
|
47
|
-
Use targeted checks where needed to verify a regrouped ticket. Run the full
|
|
48
|
-
gate once at the completed branch tip, through /review-diff. Rewriting changes
|
|
49
|
-
the review endpoints, so the next review covers the full rewritten branch;
|
|
50
|
-
mark the old coverage superseded even if the tip's tree is identical. After a
|
|
51
|
-
review requests fixes, finish the whole fix batch, fold it into these same
|
|
52
|
-
ticket commits, and repeat this completion check before the next review.
|