@sema-agent/core
Version:
Stateless, task-oriented AI agent core
206 lines (205 loc) • 8.62 kB
JavaScript
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { atomicWriteFile, ensureDir } from "../fs-atomic.js";
export class AdoptionError extends Error {
code;
constructor(code, message) {
super(message);
this.code = code;
this.name = "AdoptionError";
}
}
export const ROOT_ADOPTION_FILE = "adoption.json";
export const NOT_MIGRATED_BY_DESIGN = [
{ asset: "usage-window", ruling: "183-D1" },
{ asset: "approval-history-fields", ruling: "183-D2" },
{ asset: "sessions/<pid>.json", ruling: "3356-cli-enum" },
{ asset: "session-env/<sessionId>/*.sh", ruling: "3356-cli-enum" },
{ asset: "sema-ca.crt", ruling: "3356-cli-enum" },
{ asset: "backups/", ruling: "3356-cli-enum" },
{ asset: "config-lkg-*", ruling: "3356-cli-enum" },
];
export const BASELINE_CONFIG_IDENTITIES = [
{ deployment: "web-client-bff", key: "injected-principal" },
{ deployment: "cli", key: "cloud-credentials+profiles" },
{ deployment: "cli", key: "SEMA_LIVE_PRINCIPAL" },
{ deployment: "env", key: "REQUIRE_PRINCIPAL" },
{ deployment: "core-decl", key: "localOwnerRules" },
];
function isSource(v) {
if (v === null || typeof v !== "object")
return false;
const s = v;
if (s.kind === "local-owner")
return true;
return s.kind === "principal" && typeof s.principal === "string" && s.principal !== "";
}
function isRootAdoptionFileShape(v) {
if (v === null || typeof v !== "object")
return false;
const f = v;
if (f.schemaVersion !== 1)
return false;
if ("marker" in f && !("adopted" in f)) {
const m = f.marker;
if (m === null ||
typeof m !== "object" ||
typeof m.adoptionId !== "string" ||
!isSource(m.from) ||
typeof m.toPrincipal !== "string" ||
typeof m.phase !== "number" ||
![2, 3, 4, 5].includes(m.phase)) {
return false;
}
const p = m.plan;
if (p === null ||
p === undefined ||
typeof p !== "object" ||
(p.rulesDir !== undefined && typeof p.rulesDir !== "string") ||
!Array.isArray(p.carriage) ||
!p.carriage.every((s) => typeof s === "string") ||
typeof p.credentialsRef !== "string") {
return false;
}
if (m.legs !== undefined) {
if (m.legs === null || typeof m.legs !== "object" || Array.isArray(m.legs))
return false;
const okCount = (n) => n === undefined || (typeof n === "number" && Number.isSafeInteger(n) && n >= 0);
for (const bit of Object.values(m.legs)) {
if (bit === null || typeof bit !== "object")
return false;
const b = bit;
if (b.done !== true || !okCount(b.rows) || !okCount(b.quarantined))
return false;
}
}
const legs = (m.legs ?? {});
if (m.phase >= 3 && legs["session-policy"]?.done !== true)
return false;
if (m.phase === 5) {
for (const store of p.carriage) {
if (legs[`carriage:${store}`]?.done !== true)
return false;
}
}
const planned = new Set(p.carriage);
for (const key of Object.keys(legs)) {
if (key.startsWith("carriage:") && !planned.has(key.slice("carriage:".length)))
return false;
}
return true;
}
if ("adopted" in f && !("marker" in f)) {
const a = f.adopted;
if (a === null ||
typeof a !== "object" ||
!isSource(a.from) ||
typeof a.toPrincipal !== "string" ||
typeof a.atMs !== "number" ||
a.immutableReport === null ||
typeof a.immutableReport !== "object") {
return false;
}
const r = a.immutableReport;
const sameFrom = isSource(r.from) &&
(r.from.kind === "local-owner"
? a.from.kind === "local-owner"
: a.from.kind === "principal" &&
r.from.principal === a.from.principal);
const okCount = (n) => n === undefined || (typeof n === "number" && Number.isSafeInteger(n) && n >= 0);
const configIds = new Set();
const configsOk = Array.isArray(r.affectedDeploymentConfigs) &&
r.affectedDeploymentConfigs.length > 0 &&
r.affectedDeploymentConfigs.every((c) => {
if (c === null || typeof c !== "object")
return false;
const e = c;
if (typeof e.deployment !== "string" || e.deployment === "" || typeof e.key !== "string" || e.key === "")
return false;
if (typeof e.requiredValue !== "string" || typeof e.migrated !== "boolean")
return false;
const id = JSON.stringify([e.deployment, e.key]);
if (configIds.has(id))
return false;
configIds.add(id);
return true;
});
const nmd = r.notMigratedByDesign;
const nmdAssets = new Set();
const closedSetOk = Array.isArray(nmd) &&
nmd.length > 0 &&
nmd.every((e) => {
if (e === null || typeof e !== "object")
return false;
const m = e;
if (typeof m.asset !== "string" || m.asset === "" || typeof m.ruling !== "string" || m.ruling === "")
return false;
if (nmdAssets.has(m.asset))
return false;
nmdAssets.add(m.asset);
return true;
});
const legsOk = Array.isArray(r.legs) &&
r.legs.every((l) => {
if (l === null || typeof l !== "object")
return false;
const e = l;
return (typeof e.store === "string" &&
typeof e.action === "string" &&
["bucket-rebind", "row-rewrite", "carried", "none", "reset"].includes(e.action) &&
okCount(e.rows) &&
okCount(e.quarantined));
});
const credsOk = r.credentials !== null &&
typeof r.credentials === "object" &&
r.credentials.issuedBy === "server" &&
typeof r.credentials.ref === "string" &&
r.credentials.ref !== "";
return (typeof r.adoptionId === "string" &&
r.toPrincipal === a.toPrincipal &&
r.atMs === a.atMs &&
Number.isSafeInteger(a.atMs) &&
a.atMs >= 0 &&
sameFrom &&
closedSetOk &&
configsOk &&
legsOk &&
credsOk);
}
return false;
}
export function readRootAdoptionFile(root) {
let raw;
try {
raw = readFileSync(join(root, ROOT_ADOPTION_FILE), "utf8");
}
catch (err) {
if (err.code === "ENOENT")
return undefined;
throw new AdoptionError("adoption_marker_corrupt", `could not read the adoption marker in ${root}: ${err.message}`);
}
let parsed;
try {
parsed = JSON.parse(raw);
}
catch (err) {
throw new AdoptionError("adoption_marker_corrupt", `the adoption marker in ${root} is not valid JSON (${err.message}) — refusing to serve this data root until it is repaired`);
}
if (!isRootAdoptionFileShape(parsed)) {
throw new AdoptionError("adoption_marker_corrupt", `the adoption marker in ${root} does not carry a readable shape — refusing to serve this data root until it is repaired`);
}
return parsed;
}
export function writeRootAdoptionFile(root, content) {
ensureDir(root);
atomicWriteFile(join(root, "tmp"), join(root, ROOT_ADOPTION_FILE), JSON.stringify(content, null, 2));
}
export function assertAdoptionBootGate(root, storeName) {
const f = readRootAdoptionFile(root);
if (f !== undefined && "marker" in f) {
const from = f.marker.from.kind === "principal" ? `principal "${f.marker.from.principal}"` : "the local owner";
throw new AdoptionError("adoption_in_flight", `${storeName}: an adoption of this data root (${from} → "${f.marker.toPrincipal}", phase ${f.marker.phase}) is in flight — ` +
`resume adoptLocalDataRoot to completion (or repair ${join(root, ROOT_ADOPTION_FILE)}) before constructing stores over it; ` +
`serving a half-migrated root is refused`);
}
}