feat(queue): queue as data A2, migration, render and dispatch (#1508)
Filbert approved round 1 (f167b85e). Manifest 782bcb62, 21 files, plus the QUEUE.md markers and the TOOLS.md section. Lead decision 35. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -9,9 +9,9 @@ import { isAbsolute, join, resolve as resolvePath } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { QueueError } from "./errors.mjs";
|
||||
import { checkPlatform, errno, fsyncFile, lstatOrNull, readOrNull, realIo, unlinkQuiet, writeTemp } from "./io.mjs";
|
||||
import { acquire, checkGate, realProc, release, unlock as unlockLock } from "./lock.mjs";
|
||||
import { acquire, checkGate, realProc, releaseOrWarn, unlock as unlockLock } from "./lock.mjs";
|
||||
import {
|
||||
CALLER_OP_RE, PRIVILEGED, SEMANTICS, VERSION, applyEntry, buildDoc, canonArgs, checkName, classifyView, countHeading,
|
||||
PRIVILEGED, SEMANTICS, VERSION, applyEntry, buildDoc, canonArgs, checkCallerOpId, checkName, classifyView, countHeading,
|
||||
describeUnshown, genesisReceipt, genesisRows, gitBlobId, loadDoc, logDigest, nextFor, parseBriefSpec, parseManifest,
|
||||
parseMigrationMap, render, rowsArray, sameJson, serialize, sha256, splitView,
|
||||
} from "./queue.mjs";
|
||||
@@ -95,6 +95,14 @@ function actorOf(ctx, by) {
|
||||
return checkName(name, "actor");
|
||||
}
|
||||
|
||||
// N12: --by wins over MOSAIC_AGENT_NAME, and a difference is worth a line on
|
||||
// stderr. Both are self-asserted (J2), so nothing is logged.
|
||||
function actorMismatch(ctx, by) {
|
||||
const env = ctx.env.MOSAIC_AGENT_NAME;
|
||||
if (by === null || by === undefined || env === undefined || env === "" || by === env) return null;
|
||||
return `warning: --by ${JSON.stringify(by)} differs from MOSAIC_AGENT_NAME=${JSON.stringify(env)}`;
|
||||
}
|
||||
|
||||
function isSeatDir(top, name) {
|
||||
try {
|
||||
return lstatSync(join(top, "agents", name)).isDirectory();
|
||||
@@ -417,8 +425,7 @@ function withLock(ctx, loc, { op = null, verb }, fn) {
|
||||
} catch (err) {
|
||||
failure = err;
|
||||
}
|
||||
let msg;
|
||||
try { msg = release(handle, ctx.io); } catch (err) { msg = `cannot release the queue lock (${errno(err)})`; }
|
||||
const msg = releaseOrWarn(handle, ctx.io);
|
||||
// A refusal still reports what release found (8.4).
|
||||
if (msg && failure instanceof Error) failure.message += `\nwarning: ${msg}`;
|
||||
else if (msg) res.err.push(`warning: ${msg}`);
|
||||
@@ -428,8 +435,7 @@ function withLock(ctx, loc, { op = null, verb }, fn) {
|
||||
|
||||
function checkCallerOp(op) {
|
||||
if (typeof op !== "string" || op === "") throw new QueueError("--op ID is required; choose it before the first attempt and reuse it on every retry", 4);
|
||||
if (!CALLER_OP_RE.test(op)) throw refuse(`op id ${JSON.stringify(op)} must match ${CALLER_OP_RE.source} (8 to 72 characters)`);
|
||||
if (op.endsWith(".outcome")) throw refuse(`op ids ending in .outcome are reserved`);
|
||||
checkCallerOpId(op);
|
||||
}
|
||||
|
||||
// --- mutations ---
|
||||
@@ -456,6 +462,18 @@ function resolveFor(ctx, loc, cur, verb, args, cmp) {
|
||||
// it is not part of the op's identity.
|
||||
export function mutate(opts, { verb, op, args, by, yes = false }) {
|
||||
const ctx = makeCtx(opts);
|
||||
const mismatch = actorMismatch(ctx, by);
|
||||
try {
|
||||
const res = mutateAs(ctx, { verb, op, args, by, yes });
|
||||
if (mismatch) res.err.unshift(mismatch);
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (mismatch && err instanceof Error) err.message += `\n${mismatch}`;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function mutateAs(ctx, { verb, op, args, by, yes }) {
|
||||
checkCallerOp(op);
|
||||
const actor = actorOf(ctx, by);
|
||||
const cargs = canonArgs(verb, args);
|
||||
@@ -776,6 +794,6 @@ export function unlock(opts, { checkGateOnly = false } = {}) {
|
||||
const ctx = makeCtx(opts);
|
||||
const loc = unlockLoc(ctx);
|
||||
if (checkGateOnly) return { out: [checkGate({ gitDir: loc.gitDir, io: ctx.io, proc: ctx.proc }).line], err: [], code: 0 };
|
||||
const [line, ...warnings] = unlockLock({ gitDir: loc.gitDir, io: ctx.io, proc: ctx.proc, hook: ctx.hook }).split("\n");
|
||||
return { out: [line], err: warnings, code: 0 };
|
||||
const { result, warning } = unlockLock({ gitDir: loc.gitDir, io: ctx.io, proc: ctx.proc, hook: ctx.hook });
|
||||
return { out: [result], err: warning ? [`warning: ${warning}`] : [], code: 0 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user