scripts: land-work turns a resolved merge decision into a gated local commit (row 116, #1610)
Candidate manifest 8b4ab31014a124ec0e3abba44238976d6f4c9af48cbdb36c2c77d18f0137f888 from Darkwing's round 2 packet (0a4076e8e), on BASE1223a0f37. No manifest path changed between BASE and the landing target. Filbert approved round 2 in 28468, closing C1 and D1 from round 1 (28464). Sage reran the full gate at the landing target with the candidate applied. The replay acceptance follows ruling sage-0204. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env node
|
||||
// Test fixture for land-work (row 116, #1610): writes rows into a bus
|
||||
// database through the real Store, so the schema and its digest are the
|
||||
// Store's own and land-work's read check passes.
|
||||
//
|
||||
// node scripts/land-work/fixture.mjs <dataRoot> <rows.json>
|
||||
//
|
||||
// rows.json is an array of { "table": "decisions" | "decision_events" |
|
||||
// "events", ...columns }. Rows go in in array order, in one transaction.
|
||||
// Object values (body, options) are stored as JSON text. A missing `at` is
|
||||
// now, a missing events or decisions `id` is a fresh UUID, and decisions
|
||||
// default to the shape a PM's merge raise has. The data root is made if
|
||||
// missing. Tests only: the Store's writer lock refuses a database that
|
||||
// already has a writer.
|
||||
import { readFileSync, mkdirSync } from 'node:fs';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { Store } from '../../packages/bus/src/store.mjs';
|
||||
|
||||
const TABLES = {
|
||||
decisions: ['seq', 'id', 'at', 'business', 'project', 'raised_by_role', 'raised_by_run', 'class', 'action',
|
||||
'route_to', 'question', 'options', 'recommendation', 'task_ref', 'requirement_ref', 'blocking', 'supersedes'],
|
||||
decision_events: ['seq', 'decision', 'at', 'op', 'by', 'choice', 'note', 'via'],
|
||||
events: ['seq', 'id', 'at', 'business', 'kind', 'actor_role', 'actor_run', 'subject', 'corrects', 'body'],
|
||||
};
|
||||
const DEFAULTS = {
|
||||
decisions: { raised_by_role: 'pm', raised_by_run: 'rfixture', class: 'gated', route_to: 'human',
|
||||
recommendation: 'yes', blocking: 0 },
|
||||
decision_events: {},
|
||||
events: {},
|
||||
};
|
||||
|
||||
export function writeRows(dataRoot, rows) {
|
||||
mkdirSync(dataRoot, { recursive: true, mode: 0o700 });
|
||||
const store = new Store(dataRoot);
|
||||
try {
|
||||
store.transaction(() => {
|
||||
for (const row of rows) {
|
||||
const columns = TABLES[row.table];
|
||||
if (!columns) throw Error(`unknown table ${row.table}`);
|
||||
const r = { ...DEFAULTS[row.table], ...row };
|
||||
r.at ??= new Date().toISOString();
|
||||
if (row.table !== 'decision_events') r.id ??= randomUUID();
|
||||
const used = columns.filter((c) => r[c] !== undefined);
|
||||
const values = used.map((c) => (r[c] !== null && typeof r[c] === 'object' ? JSON.stringify(r[c]) : r[c]));
|
||||
store.run(`INSERT INTO ${row.table} (${used.join(',')}) VALUES (${used.map(() => '?').join(',')})`, ...values);
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
store.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
const [dataRoot, file] = process.argv.slice(2);
|
||||
writeRows(dataRoot, JSON.parse(readFileSync(file, 'utf8')));
|
||||
}
|
||||
Reference in New Issue
Block a user