akm-cli
Version:
akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur
597 lines (596 loc) • 27.6 kB
JavaScript
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
import { cloneExecutionJsonObject } from "../execution/json.js";
import { isRecord } from "./common.js";
import { IMPROVE_PROCESS_NAMES } from "./config/engine-semantics.js";
const COMMON_FIELDS = [
"schemaVersion",
"ok",
"scope",
"dryRun",
"notices",
"skipped",
"guidance",
"memorySummary",
"memoryCleanup",
"cyclesRun",
"plannedRefs",
"plan",
"actions",
"skippedProcesses",
"engineProbe",
"distillSkipped",
"validationFailures",
"schemaRepairs",
"consolidation",
"extract",
"lintSummary",
"memoryIndexHealth",
"coverageGaps",
// R10: no longer written (the write-only eval-cases path was removed),
// but kept in the allow-list so `decodeImproveResult` still reads
// improve-result envelopes a prior release wrote with this field —
// AGENTS.md "Reading persisted data".
"evalCasesWritten",
"deadUrls",
"deadUrlCoverage",
"reflectsWithErrorContext",
"memoryInference",
// 0.9.17-alpha.9: no longer written (the LLM entity-graph extraction that
// wrote these was retired), kept readable for the same reason as
// `evalCasesWritten` above.
"graphExtraction",
"memoryInferenceDurationMs",
"graphExtractionDurationMs",
"ensureIndexDurationMs",
"orphansPurged",
"proposalsExpired",
"reflectCooldownActions",
"reflectSkippedActions",
"reflectGuardRejectedActions",
// No longer written (nothing has set it since the confidence gate was
// deleted), but kept in the allow-list so `decodeImproveResult` still reads
// the improve_runs rows an older release wrote with it, its value ignored —
// AGENTS.md "Reading persisted data".
"gateAutoAcceptedCount",
"gateAutoAcceptFailedCount",
"triage",
"proactiveMaintenance",
"cycleMetrics",
"runId",
"sync",
"writtenPaths",
"terminated",
"usageReport",
];
const V2_FIELDS = new Set([...COMMON_FIELDS, "strategy", "strategyFilteredRefs"]);
function fail(message) {
throw new Error(`invalid improve-result envelope: ${message}`);
}
function requireExactFields(value, allowed) {
const unknown = Object.keys(value).filter((key) => !allowed.has(key));
if (unknown.length > 0)
fail(`unknown field${unknown.length === 1 ? "" : "s"}: ${unknown.sort().join(", ")}`);
}
function requireNumber(value, field, path) {
if (typeof value[field] !== "number" || !Number.isFinite(value[field]))
fail(`${path}.${field} must be a number`);
}
function requireCount(value, field, path) {
requireNumber(value, field, path);
if (!Number.isSafeInteger(value[field]) || value[field] < 0) {
fail(`${path}.${field} must be a non-negative integer`);
}
}
function validateLoweringNotices(value) {
if (!Array.isArray(value))
fail("notices must be an array");
for (let index = 0; index < value.length; index += 1) {
const notice = value[index];
if (!isRecord(notice))
fail(`notices[${index}] must be an object`);
requireExactFields(notice, new Set(["code", "severity", "adapter", "field", "message", "details"]));
for (const field of ["code", "adapter", "message"]) {
if (typeof notice[field] !== "string")
fail(`notices[${index}].${field} must be a string`);
}
if (notice.severity !== "info" && notice.severity !== "warning") {
fail(`notices[${index}].severity is invalid`);
}
if (notice.field !== undefined && notice.field !== null && typeof notice.field !== "string") {
fail(`notices[${index}].field must be a string or null`);
}
if (notice.details !== undefined && notice.details !== null) {
try {
cloneExecutionJsonObject(notice.details, `notices[${index}].details`);
}
catch {
fail(`notices[${index}].details must be a JSON object or null`);
}
}
}
}
function validateConsolidationPlan(value) {
if (!isRecord(value))
fail("plan.consolidation must be an object");
requireExactFields(value, new Set([
"configured",
"effective",
"poolSize",
"candidatePoolSize",
"gates",
"wouldRun",
"reason",
"estimatedChunks",
]));
if (!isRecord(value.configured))
fail("plan.consolidation.configured must be an object");
requireExactFields(value.configured, new Set(["enabled", "minPoolSize", "limit", "maxChunkSize"]));
if (value.configured.enabled !== undefined && typeof value.configured.enabled !== "boolean") {
fail("plan.consolidation.configured.enabled must be a boolean");
}
for (const field of ["minPoolSize", "limit", "maxChunkSize"]) {
if (value.configured[field] !== undefined && typeof value.configured[field] !== "number") {
fail(`plan.consolidation.configured.${field} must be a number`);
}
}
if (!isRecord(value.effective))
fail("plan.consolidation.effective must be an object");
requireExactFields(value.effective, new Set(["enabled", "minPoolSize", "limit", "chunkSize"]));
if (typeof value.effective.enabled !== "boolean")
fail("plan.consolidation.effective.enabled must be a boolean");
requireCount(value.effective, "minPoolSize", "plan.consolidation.effective");
requireCount(value.effective, "chunkSize", "plan.consolidation.effective");
if (value.effective.limit !== undefined && typeof value.effective.limit !== "number") {
fail("plan.consolidation.effective.limit must be a number");
}
requireCount(value, "poolSize", "plan.consolidation");
requireCount(value, "candidatePoolSize", "plan.consolidation");
requireCount(value, "estimatedChunks", "plan.consolidation");
if (typeof value.wouldRun !== "boolean")
fail("plan.consolidation.wouldRun must be a boolean");
if (typeof value.reason !== "string")
fail("plan.consolidation.reason must be a string");
if (!isRecord(value.gates))
fail("plan.consolidation.gates must be an object");
requireExactFields(value.gates, new Set(["profile", "minimumPool", "delta"]));
for (const gateName of ["profile", "minimumPool", "delta"]) {
const gate = value.gates[gateName];
if (!isRecord(gate))
fail(`plan.consolidation.gates.${gateName} must be an object`);
requireExactFields(gate, new Set(["passed", "reason"]));
if (typeof gate.passed !== "boolean" || typeof gate.reason !== "string") {
fail(`plan.consolidation.gates.${gateName} must contain boolean passed and string reason`);
}
}
}
function validateProactivePlan(value) {
if (!isRecord(value))
fail("plan.proactive must be an object");
requireExactFields(value, new Set(["configured", "effective", "candidatePool", "dueTotal", "neverReflected", "selected", "selectedRefs"]));
if (!isRecord(value.configured))
fail("plan.proactive.configured must be an object");
requireExactFields(value.configured, new Set(["dueDays", "maxPerRun", "limit"]));
for (const field of ["dueDays", "maxPerRun", "limit"]) {
if (value.configured[field] !== undefined && typeof value.configured[field] !== "number") {
fail(`plan.proactive.configured.${field} must be a number`);
}
}
if (!isRecord(value.effective))
fail("plan.proactive.effective must be an object");
requireExactFields(value.effective, new Set(["dueDays", "maxPerRun"]));
requireNumber(value.effective, "dueDays", "plan.proactive.effective");
requireNumber(value.effective, "maxPerRun", "plan.proactive.effective");
for (const field of ["candidatePool", "dueTotal", "neverReflected", "selected"]) {
requireCount(value, field, "plan.proactive");
}
if (!Array.isArray(value.selectedRefs) || value.selectedRefs.some((ref) => typeof ref !== "string")) {
fail("plan.proactive.selectedRefs must be an array of strings");
}
if (value.selected !== value.selectedRefs.length) {
fail("plan.proactive.selected must equal plan.proactive.selectedRefs.length");
}
}
/** #947 — plan.processes: one row per IMPROVE_PROCESS_NAMES name, plus an optional "triage.judgment" row. */
function validateProcessRoutingRows(value) {
if (!Array.isArray(value))
fail("plan.processes must be an array");
const canonicalNames = IMPROVE_PROCESS_NAMES;
const engineKinds = new Set(["llm", "agent", "sdk"]);
const seen = new Set();
for (const row of value) {
if (!isRecord(row))
fail("plan.processes entries must be objects");
requireExactFields(row, new Set(["process", "enabled", "engine", "model", "engineKind", "notices", "unavailable", "eligibleRefs"]));
if (typeof row.process !== "string" ||
!(canonicalNames.includes(row.process) ||
row.process === "triage.judgment" ||
// 0.9.17-alpha.9: "graphExtraction" is no longer a process a fresh
// plan can route (the LLM entity-graph extraction it named was
// retired), but every pre-alpha.9 run recorded one here — kept
// readable, same as `stageNames`' "graph-extraction" above and
// `graphExtraction` in COMMON_FIELDS, so a historical run still
// decodes for `akm health` instead of failing this row outright.
row.process === "graphExtraction")) {
fail("plan.processes.process is invalid");
}
if (seen.has(row.process))
fail(`plan.processes must not repeat "${row.process}"`);
seen.add(row.process);
if (typeof row.enabled !== "boolean")
fail("plan.processes.enabled must be a boolean");
if (row.engine !== undefined && typeof row.engine !== "string")
fail("plan.processes.engine must be a string");
if (row.model !== undefined && typeof row.model !== "string")
fail("plan.processes.model must be a string");
if (row.engineKind !== undefined && (typeof row.engineKind !== "string" || !engineKinds.has(row.engineKind))) {
fail("plan.processes.engineKind is invalid");
}
validateLoweringNotices(row.notices);
if (row.unavailable !== undefined) {
if (!isRecord(row.unavailable))
fail("plan.processes.unavailable must be an object");
requireExactFields(row.unavailable, new Set(["configKey", "reason"]));
if (typeof row.unavailable.configKey !== "string" || typeof row.unavailable.reason !== "string") {
fail("plan.processes.unavailable must contain string configKey and reason");
}
}
if (row.eligibleRefs !== undefined)
requireCount(row, "eligibleRefs", "plan.processes entry");
}
for (const name of canonicalNames) {
if (!seen.has(name))
fail(`plan.processes must contain exactly one "${name}" row`);
}
}
function validateImprovePlan(value, dryRun, plannedRefNames) {
if (!isRecord(value))
fail("plan must be an object");
requireExactFields(value, new Set([
"mode",
"dispatch",
"snapshot",
"candidates",
"limits",
"gates",
"effectiveRefs",
"processes",
"proactive",
"consolidation",
"stages",
"triage",
]));
if (value.mode !== "estimate" && value.mode !== "execution")
fail('plan.mode must be "estimate" or "execution"');
if (typeof value.dispatch !== "boolean")
fail("plan.dispatch must be a boolean");
if ((value.mode === "estimate" && value.dispatch) || (value.mode === "execution" && !value.dispatch)) {
fail("plan.dispatch must be false for estimate mode and true for execution mode");
}
if (dryRun && (value.mode !== "estimate" || value.dispatch !== false)) {
fail("dryRun=true requires estimate mode with dispatch=false");
}
if (!dryRun && (value.mode !== "execution" || value.dispatch !== true)) {
fail("dryRun=false requires execution mode with dispatch=true");
}
if (!isRecord(value.snapshot))
fail("plan.snapshot must be an object");
requireExactFields(value.snapshot, new Set(["status", "reason"]));
if (typeof value.snapshot.status !== "string" ||
!new Set(["ready", "missing", "incompatible", "unknown"]).has(value.snapshot.status)) {
fail("plan.snapshot.status is invalid");
}
if (typeof value.snapshot.reason !== "string")
fail("plan.snapshot.reason must be a string");
if (!isRecord(value.candidates))
fail("plan.candidates must be an object");
requireExactFields(value.candidates, new Set(["rawInScope", "selected", "effective"]));
for (const field of ["rawInScope", "selected", "effective"]) {
requireCount(value.candidates, field, "plan.candidates");
}
if (value.candidates.rawInScope < value.candidates.selected) {
fail("plan.candidates.rawInScope cannot be less than plan.candidates.selected");
}
if (value.candidates.selected < value.candidates.effective) {
fail("plan.candidates.selected cannot be less than plan.candidates.effective");
}
if (!isRecord(value.limits))
fail("plan.limits must be an object");
requireExactFields(value.limits, new Set(["configured", "effective", "additiveReplayAllowance", "totalCeiling"]));
if (!isRecord(value.limits.configured))
fail("plan.limits.configured must be an object");
requireExactFields(value.limits.configured, new Set(["cli", "profile", "reflect"]));
for (const field of ["cli", "profile", "reflect"]) {
if (value.limits.configured[field] !== undefined)
requireCount(value.limits.configured, field, "plan.limits.configured");
}
if (value.limits.effective !== undefined)
requireCount(value.limits, "effective", "plan.limits");
requireCount(value.limits, "additiveReplayAllowance", "plan.limits");
if (value.limits.totalCeiling !== undefined)
requireCount(value.limits, "totalCeiling", "plan.limits");
if (value.limits.effective === undefined && value.limits.totalCeiling !== undefined) {
fail("plan.limits.totalCeiling must be omitted when plan.limits.effective is unbounded");
}
if (value.limits.effective !== undefined &&
value.limits.totalCeiling !== value.limits.effective + value.limits.additiveReplayAllowance) {
fail("plan.limits.totalCeiling must equal plan.limits.effective + plan.limits.additiveReplayAllowance");
}
const gateNames = new Set(["profile", "cleanup", "validation", "signal", "disk", "limit"]);
// Plans stored before 0.9.17-alpha.7 (#986) have no retrieval gate.
const optionalGateNames = new Set(["retrieval"]);
if (!Array.isArray(value.gates))
fail("plan.gates must be an array");
const gateRemovedByName = new Map();
for (const gate of value.gates) {
if (!isRecord(gate))
fail("plan.gates entries must be objects");
requireExactFields(gate, new Set(["name", "removed", "reason"]));
if (typeof gate.name !== "string" || !(gateNames.has(gate.name) || optionalGateNames.has(gate.name))) {
fail("plan.gates.name is invalid");
}
requireCount(gate, "removed", "plan.gates entry");
if (typeof gate.reason !== "string")
fail("plan.gates.reason must be a string");
if (gateRemovedByName.has(gate.name))
fail(`plan.gates must contain exactly one ${gate.name} gate`);
gateRemovedByName.set(gate.name, gate.removed);
}
for (const gateName of gateNames) {
if (!gateRemovedByName.has(gateName))
fail(`plan.gates must contain exactly one ${gateName} gate`);
}
const preLimitRemoved = [...gateRemovedByName]
.filter(([gateName]) => gateName !== "limit")
.reduce((total, [, removed]) => total + removed, 0);
if (preLimitRemoved !== value.candidates.rawInScope - value.candidates.selected) {
fail("plan pre-limit gate removals must equal plan.candidates.rawInScope - plan.candidates.selected");
}
if (gateRemovedByName.get("limit") !==
value.candidates.selected - value.candidates.effective) {
fail("plan limit removal must equal plan.candidates.selected - plan.candidates.effective");
}
const lanes = new Set([
"scope",
"signal-delta",
"proactive",
"high-salience",
"distill-only",
"forgetting-safety",
"replay",
"unknown",
]);
const reasons = new Set(["scope-ref", "scope-type", "memory-cleanup", "strategy_filtered_all_passes"]);
if (!Array.isArray(value.effectiveRefs))
fail("plan.effectiveRefs must be an array");
for (const entry of value.effectiveRefs) {
if (!isRecord(entry))
fail("plan.effectiveRefs entries must be objects");
requireExactFields(entry, new Set(["ref", "lane", "reason"]));
if (typeof entry.ref !== "string")
fail("plan.effectiveRefs.ref must be a string");
if (typeof entry.lane !== "string" || !lanes.has(entry.lane))
fail("plan.effectiveRefs.lane is invalid");
if (typeof entry.reason !== "string" || !reasons.has(entry.reason))
fail("plan.effectiveRefs.reason is invalid");
}
if (value.candidates.effective !== value.effectiveRefs.length) {
fail("plan.candidates.effective must equal plan.effectiveRefs.length");
}
const effectiveRefNames = value.effectiveRefs.map((entry) => entry.ref);
if (new Set(effectiveRefNames).size !== effectiveRefNames.length) {
fail("plan.effectiveRefs must not contain duplicate refs");
}
if (plannedRefNames.length !== effectiveRefNames.length ||
plannedRefNames.some((ref, index) => ref !== effectiveRefNames[index])) {
fail("plannedRefs must contain the same refs in the same order as plan.effectiveRefs");
}
const replayCount = value.effectiveRefs.filter((entry) => entry.lane === "replay").length;
const ordinaryCount = value.effectiveRefs.length - replayCount;
if (replayCount > value.limits.additiveReplayAllowance) {
fail("plan replay refs cannot exceed plan.limits.additiveReplayAllowance");
}
if (value.limits.effective !== undefined && ordinaryCount > value.limits.effective) {
fail("plan ordinary refs cannot exceed plan.limits.effective");
}
if (value.limits.totalCeiling !== undefined && value.effectiveRefs.length > value.limits.totalCeiling) {
fail("plan.effectiveRefs cannot exceed plan.limits.totalCeiling");
}
// #947 added plan.processes (2026-09-09T09:03:19Z); every run recorded
// before it legitimately stored `plan` with no `processes` key at all —
// validate the rows only when present, same as `proactive` below, so a
// pre-#947 envelope still decodes (AGENTS.md "Reading persisted data").
if (value.processes !== undefined)
validateProcessRoutingRows(value.processes);
if (value.proactive !== undefined)
validateProactivePlan(value.proactive);
validateConsolidationPlan(value.consolidation);
// "graph-extraction" is no longer a stage a fresh plan can name — retired
// 0.9.17-alpha.9 — but stays here so a historical envelope that captured a
// dry-run plan before the retirement still decodes.
const stageNames = new Set(["consolidation", "extract", "graph-extraction", "memory-inference"]);
if (!Array.isArray(value.stages))
fail("plan.stages must be an array");
for (const stage of value.stages) {
if (!isRecord(stage))
fail("plan.stages entries must be objects");
requireExactFields(stage, new Set(["name", "wouldRun", "reason"]));
if (typeof stage.name !== "string" || !stageNames.has(stage.name))
fail("plan.stages.name is invalid");
if (typeof stage.wouldRun !== "boolean" || typeof stage.reason !== "string") {
fail("plan.stages entries must contain boolean wouldRun and string reason");
}
}
if (!isRecord(value.triage))
fail("plan.triage must be an object");
requireExactFields(value.triage, new Set(["enabled", "configuredMode", "mode", "maxAcceptsPerRun", "maxDiffLines"]));
if (typeof value.triage.enabled !== "boolean")
fail("plan.triage.enabled must be a boolean");
for (const field of ["configuredMode", "mode"]) {
if (value.triage[field] !== "queue" && value.triage[field] !== "promote") {
fail(`plan.triage.${field} must be queue or promote`);
}
}
requireCount(value.triage, "maxAcceptsPerRun", "plan.triage");
if (value.triage.maxDiffLines !== undefined && typeof value.triage.maxDiffLines !== "number") {
fail("plan.triage.maxDiffLines must be a number");
}
}
function validateCommon(value) {
if (typeof value.ok !== "boolean")
fail("ok must be a boolean");
if (typeof value.dryRun !== "boolean")
fail("dryRun must be a boolean");
if (!Array.isArray(value.plannedRefs))
fail("plannedRefs must be an array");
if (value.notices !== undefined)
validateLoweringNotices(value.notices);
const plannedRefNames = value.plannedRefs.map((entry, index) => {
if (!isRecord(entry) || typeof entry.ref !== "string")
fail(`plannedRefs[${index}].ref must be a string`);
return entry.ref;
});
if (value.plan !== undefined)
validateImprovePlan(value.plan, value.dryRun, plannedRefNames);
if (!isRecord(value.scope))
fail("scope must be an object");
requireExactFields(value.scope, new Set(["mode", "value"]));
if (value.scope.mode !== "all" && value.scope.mode !== "type" && value.scope.mode !== "ref") {
fail('scope.mode must be "all", "type", or "ref"');
}
if (value.scope.value !== undefined && typeof value.scope.value !== "string") {
fail("scope.value must be a string when present");
}
if (!isRecord(value.memorySummary))
fail("memorySummary must be an object");
requireExactFields(value.memorySummary, new Set(["eligible", "derived"]));
if (typeof value.memorySummary.eligible !== "number" || typeof value.memorySummary.derived !== "number") {
fail("memorySummary.eligible and memorySummary.derived must be numbers");
}
for (const field of [
"actions",
"skippedProcesses",
"engineProbe",
"validationFailures",
"schemaRepairs",
"extract",
"coverageGaps",
"deadUrls",
"writtenPaths",
]) {
if (value[field] !== undefined && !Array.isArray(value[field]))
fail(`${field} must be an array`);
}
if (Array.isArray(value.writtenPaths) && value.writtenPaths.some((entry) => typeof entry !== "string")) {
fail("writtenPaths must be an array of strings");
}
for (const field of [
"cyclesRun",
// R10: retired write, kept readable — see the COMMON_FIELDS comment above.
"evalCasesWritten",
"reflectsWithErrorContext",
"memoryInferenceDurationMs",
"graphExtractionDurationMs",
"ensureIndexDurationMs",
"orphansPurged",
"proposalsExpired",
"reflectCooldownActions",
"reflectSkippedActions",
"reflectGuardRejectedActions",
"gateAutoAcceptFailedCount",
]) {
if (value[field] !== undefined && typeof value[field] !== "number")
fail(`${field} must be a number`);
}
for (const field of ["guidance", "runId"]) {
if (value[field] !== undefined && typeof value[field] !== "string")
fail(`${field} must be a string`);
}
for (const field of [
"skipped",
"memoryCleanup",
"distillSkipped",
"consolidation",
"lintSummary",
"memoryIndexHealth",
"memoryInference",
"graphExtraction",
"triage",
"proactiveMaintenance",
"cycleMetrics",
"sync",
"terminated",
"plan",
"deadUrlCoverage",
"usageReport",
]) {
if (value[field] !== undefined && !isRecord(value[field]))
fail(`${field} must be an object`);
}
if (isRecord(value.terminated)) {
requireExactFields(value.terminated, new Set(["reason", "at", "errorMessage"]));
if (typeof value.terminated.reason !== "string" || typeof value.terminated.at !== "string") {
fail("terminated.reason and terminated.at must be strings");
}
if (value.terminated.errorMessage !== undefined && typeof value.terminated.errorMessage !== "string") {
fail("terminated.errorMessage must be a string when present");
}
}
if (isRecord(value.deadUrlCoverage)) {
requireExactFields(value.deadUrlCoverage, new Set(["checked", "total", "skipped"]));
for (const field of ["checked", "total", "skipped"]) {
requireCount(value.deadUrlCoverage, field, "deadUrlCoverage");
}
}
}
/**
* Per-`schemaVersion` decoders for the persisted `improve_runs.result_json`
* contract, keyed by the literal `schemaVersion` value each accepts.
*
* #866 item 5 / read-shim policy (same shape as the version router in
* src/tasks/source/parse-task-source.ts, which this mirrors): every
* `schemaVersion` this build understands gets its own entry here, so
* decoding never regresses to "reject every row" the day the version bumps
* — it only stops accepting the ONE version that changed shape. All 1,539
* live rows today are v2; when a v3 shape is introduced, add a `3` entry
* (and, if v2 rows must keep reading under the newer runtime, keep this `2`
* entry as-is — every caller already skip-and-counts a decode failure, so a
* genuinely unreadable old row degrades to "excluded from metrics", never a
* crash). Do not remove the `2` entry when adding `3` unless the schema
* bump is known to be a strict superset callers can validate with it.
*/
const SCHEMA_DECODERS = {
2: (parsed) => {
requireExactFields(parsed, V2_FIELDS);
validateCommon(parsed);
if (typeof parsed.strategy !== "string" || parsed.strategy.length === 0) {
fail("strategy must be a non-empty string");
}
if (parsed.strategyFilteredRefs !== undefined && !Array.isArray(parsed.strategyFilteredRefs)) {
fail("strategyFilteredRefs must be an array");
}
return {
envelope: parsed,
strategy: parsed.strategy,
};
},
};
/** Decode the persisted public result contract. */
export function decodeImproveResult(input) {
let parsed = input;
if (typeof input === "string") {
try {
parsed = JSON.parse(input);
}
catch {
fail("not valid JSON");
}
}
if (!isRecord(parsed))
fail("root must be an object");
const decoder = typeof parsed.schemaVersion === "number" ? SCHEMA_DECODERS[parsed.schemaVersion] : undefined;
if (decoder)
return decoder(parsed);
fail(`unsupported schemaVersion: ${String(parsed.schemaVersion)}`);
}