-
Notifications
You must be signed in to change notification settings - Fork 0
306 lines (273 loc) · 12.2 KB
/
create-p0x-subtasks.yml
File metadata and controls
306 lines (273 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
name: Create P0-X Subtask Issues
# One-shot workflow: creates the seven individually tracked subtasks for
# Issue #56 (P0-X: Fix Architectural Naming Drift) and links each one back
# to the parent with a "Part of #56" reference.
# Run this once after the branch is merged; re-running is idempotent
# (skips any subtask whose title already exists).
on:
workflow_dispatch:
inputs:
dry_run:
description: "Print actions without creating any issues (true/false)"
required: false
default: "false"
type: choice
options:
- "false"
- "true"
permissions:
issues: write
jobs:
create-subtasks:
runs-on: ubuntu-latest
steps:
- name: Create P0-X1 through P0-X7 subtask issues
uses: actions/github-script@v7
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const PARENT = 56;
const DRY_RUN = '${{ inputs.dry_run }}' === 'true';
// Must match the GitHub milestone title exactly (character-for-character).
// The em dash (—) is U+2014. Verify in repository Settings → Milestones.
const MILESTONE_TITLE = 'v0.1 \u2014 Minimal Viable';
// ------------------------------------------------------------------
// Subtask definitions (one entry per P0-X checklist item in #56)
// ------------------------------------------------------------------
const subtasks = [
{
id: 'P0-X1',
title: '[P0-X1] Rename MetroidNeighbor → SemanticNeighbor',
labels: ['P0: critical', 'layer: foundation', 'layer: storage', 'task'],
body: `**Parent issue:** #${PARENT}
**Objective:**
Rename the \`MetroidNeighbor\` type to \`SemanticNeighbor\` throughout the codebase.
**Files to modify:**
- \`core/types.ts\` — rename type declaration
- \`storage/IndexedDbMetadataStore.ts\` — update all references
- All test files that reference \`MetroidNeighbor\`
- JSDoc and inline comments
**Exit criteria:**
- [ ] No occurrence of \`MetroidNeighbor\` remains in source files
- [ ] All tests pass
- [ ] Lint and typecheck clean
`,
},
{
id: 'P0-X2',
title: '[P0-X2] Rename MetroidSubgraph → SemanticNeighborSubgraph',
labels: ['P0: critical', 'layer: foundation', 'layer: storage', 'layer: cortex', 'task'],
body: `**Parent issue:** #${PARENT}
**Objective:**
Rename the \`MetroidSubgraph\` type to \`SemanticNeighborSubgraph\`.
**Files to modify:**
- \`core/types.ts\` — rename type declaration
- \`storage/IndexedDbMetadataStore.ts\` — update all references
- \`cortex/Query.ts\` — update all references
- JSDoc and inline comments
**Exit criteria:**
- [ ] No occurrence of \`MetroidSubgraph\` remains in source files
- [ ] All tests pass
- [ ] Lint and typecheck clean
`,
},
{
id: 'P0-X3',
title: '[P0-X3] Rename MetadataStore proximity-graph methods',
labels: ['P0: critical', 'layer: foundation', 'layer: storage', 'layer: cortex', 'task'],
body: `**Parent issue:** #${PARENT}
**Objective:**
Rename all MetadataStore methods that refer to the proximity graph:
| Old name | New name |
|---|---|
| \`putMetroidNeighbors\` | \`putSemanticNeighbors\` |
| \`getMetroidNeighbors\` | \`getSemanticNeighbors\` |
| \`getInducedMetroidSubgraph\` | \`getInducedNeighborSubgraph\` |
| \`needsMetroidRecalc\` | \`needsNeighborRecalc\` |
| \`flagVolumeForMetroidRecalc\` | \`flagVolumeForNeighborRecalc\` |
| \`clearMetroidRecalcFlag\` | \`clearNeighborRecalcFlag\` |
**Files to modify:**
- \`core/types.ts\` — MetadataStore interface
- \`storage/IndexedDbMetadataStore.ts\` — implementation + all callers
- \`cortex/Query.ts\` — all callers
- All test files that call these methods
**Exit criteria:**
- [ ] No method named \`*Metroid*\` exists on MetadataStore
- [ ] All tests pass
- [ ] Lint and typecheck clean
`,
},
{
id: 'P0-X4',
title: '[P0-X4] Rename planned file FastMetroidInsert → FastNeighborInsert',
labels: ['P0: critical', 'layer: hippocampus', 'task'],
body: `**Parent issue:** #${PARENT}
**Objective:**
Rename the planned Hippocampus file and class for inserting proximity neighbors.
**Files to modify/create:**
- Rename \`hippocampus/FastMetroidInsert.ts\` → \`hippocampus/FastNeighborInsert.ts\`
- Rename class/function to \`FastNeighborInsert\` / \`insertSemanticNeighbors\`
- Update any imports that reference the old path
**Exit criteria:**
- [ ] No file named \`FastMetroidInsert.ts\` exists
- [ ] No symbol named \`FastMetroidInsert\` exists in source
- [ ] Lint and typecheck clean
`,
},
{
id: 'P0-X5',
title: '[P0-X5] Rename planned file FullMetroidRecalc → FullNeighborRecalc',
labels: ['P0: critical', 'layer: daydreamer', 'task'],
body: `**Parent issue:** #${PARENT}
**Objective:**
Rename the planned Daydreamer file and class for full neighbor recalculation.
**Files to modify/create:**
- Rename \`daydreamer/FullMetroidRecalc.ts\` → \`daydreamer/FullNeighborRecalc.ts\`
- Rename class/function to \`FullNeighborRecalc\` / \`runNeighborRecalc\`
- Update any imports that reference the old path
**Exit criteria:**
- [ ] No file named \`FullMetroidRecalc.ts\` exists
- [ ] No symbol named \`FullMetroidRecalc\` exists in source
- [ ] Lint and typecheck clean
`,
},
{
id: 'P0-X6',
title: '[P0-X6] Rename IndexedDB object store metroid_neighbors → neighbor_graph',
labels: ['P0: critical', 'layer: storage', 'task'],
body: `**Parent issue:** #${PARENT}
**Objective:**
Rename the IndexedDB object store used for the proximity graph.
**Files to modify:**
- \`storage/IndexedDbMetadataStore.ts\`
- Change store name from \`metroid_neighbors\` to \`neighbor_graph\`
- Increment \`DB_VERSION\`
- Add migration in \`applyUpgrade\`: copy data from old store to new store, then delete old store
**Exit criteria:**
- [ ] No reference to the string \`metroid_neighbors\` in source
- [ ] DB_VERSION incremented
- [ ] Migration tested (open old DB, upgrade, verify data preserved)
- [ ] All tests pass
`,
},
{
id: 'P0-X7',
title: '[P0-X7] Update all docs and JSDoc: "Metroid neighbor" → "semantic neighbor"',
labels: ['P0: critical', 'layer: documentation', 'task'],
body: `**Parent issue:** #${PARENT}
**Objective:**
Remove all remaining uses of "Metroid" from documentation and code comments
where it refers to the proximity graph (not to the \`{ m1, m2, c }\` probe type).
**Files to review:**
- \`DESIGN.md\`
- All \`*.ts\` files — JSDoc blocks and inline comments
- \`README.md\`
- Any other \`.md\` files
**Exit criteria:**
- [ ] The word "Metroid" does not appear in any doc comment where it describes the neighbor/proximity graph
- [ ] "Metroid" is reserved exclusively for the \`{ m1, m2, c }\` dialectical probe
- [ ] All tests pass
`,
},
];
// ------------------------------------------------------------------
// Resolve milestone number
// ------------------------------------------------------------------
let milestoneNumber = null;
try {
// Use per_page: 100 (API max) to handle repositories with many milestones.
const { data: milestones } = await github.rest.issues.listMilestones({
owner, repo, state: 'open', per_page: 100,
});
const m = milestones.find(x => x.title === MILESTONE_TITLE);
if (m) {
milestoneNumber = m.number;
console.log(`Resolved milestone "${MILESTONE_TITLE}" → #${milestoneNumber}`);
} else {
console.log(`Milestone "${MILESTONE_TITLE}" not found — will create issues without milestone.`);
console.log('Available milestones: ' + milestones.map(x => x.title).join(', '));
}
} catch (err) {
console.log(`Could not fetch milestones: ${err.message}`);
}
// ------------------------------------------------------------------
// Fetch existing issue titles to allow idempotent re-runs
// ------------------------------------------------------------------
const existing = new Set();
for await (const page of github.paginate.iterator(
github.rest.issues.listForRepo,
{ owner, repo, state: 'all', per_page: 100 },
)) {
for (const issue of page.data) {
// `issues.listForRepo` returns both issues and pull requests.
// Only track real issues here so idempotency isn't affected by PR titles.
if (!issue.pull_request) {
existing.add(issue.title);
}
}
}
// ------------------------------------------------------------------
// Ensure required labels exist
// ------------------------------------------------------------------
const requiredLabels = [
{ name: 'task', color: '0075ca', description: 'Implementation task' },
{ name: 'P0: critical', color: 'e11d48', description: 'Blocks dependent work' },
];
for (const lbl of requiredLabels) {
try {
await github.rest.issues.getLabel({ owner, repo, name: lbl.name });
} catch (err) {
if (err.status === 404) {
if (!DRY_RUN) {
await github.rest.issues.createLabel({ owner, repo, ...lbl });
console.log(`Created label: ${lbl.name}`);
}
} else {
console.log(`Unexpected error checking label "${lbl.name}": ${err.message}`);
}
}
}
// ------------------------------------------------------------------
// Create subtask issues
// ------------------------------------------------------------------
const created = [];
for (const task of subtasks) {
if (existing.has(task.title)) {
console.log(`SKIP (already exists): ${task.title}`);
continue;
}
if (DRY_RUN) {
console.log(`DRY RUN — would create: ${task.title}`);
continue;
}
const payload = {
owner, repo,
title: task.title,
body: task.body,
labels: task.labels,
};
if (milestoneNumber) payload.milestone = milestoneNumber;
const { data: issue } = await github.rest.issues.create(payload);
console.log(`Created #${issue.number}: ${issue.title}`);
created.push(issue.number);
}
// ------------------------------------------------------------------
// Post a summary comment on the parent issue
// ------------------------------------------------------------------
if (created.length > 0) {
const lines = created.map(n => `- #${n}`).join('\n');
const summaryBody =
`The following individually tracked subtask issues have been created:\n\n${lines}\n\n` +
`Each issue carries the \`P0: critical\` label` +
(milestoneNumber ? ', is linked to the **v0.1 — Minimal Viable** milestone,' : ',') +
' and references this parent issue in its description.';
await github.rest.issues.createComment({
owner, repo,
issue_number: PARENT,
body: summaryBody,
});
console.log(`Posted summary comment on #${PARENT}`);
} else if (!DRY_RUN) {
console.log('All subtasks already exist — nothing created.');
}