fix(authority): track supported job types

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Sisyphus
2026-05-03 19:27:36 +00:00
parent e46d29ee93
commit 8b65fcbdb1
2 changed files with 210 additions and 0 deletions

View File

@@ -33,6 +33,10 @@ function normalizeFeatureName(value) {
return String(value ?? "").trim().toLowerCase();
}
function normalizeJobType(value) {
return String(value ?? "").trim().toLowerCase();
}
function addFeature(features, value) {
const normalized = normalizeFeatureName(value);
if (normalized) features.add(normalized);
@@ -319,6 +323,71 @@ export function collectAuthorityFeatures(payload = {}) {
return features;
}
function collectJobTypesFromArray(jobTypes, value) {
if (!Array.isArray(value)) return false;
for (const item of value) {
const normalized = normalizeJobType(item);
if (normalized) jobTypes.add(normalized);
}
return true;
}
function collectJobTypesFromEntries(jobTypes, value) {
if (!Array.isArray(value)) return false;
for (const entry of value) {
const normalized = normalizeJobType(entry?.type);
if (normalized) jobTypes.add(normalized);
}
return true;
}
function collectSupportedJobTypes(payload = {}) {
const source = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
const jobTypes = new Set();
let known = source.supportedJobTypesKnown === true;
const topLevelSupportedJobTypes = source.supportedJobTypes;
if (Array.isArray(topLevelSupportedJobTypes)) {
collectJobTypesFromArray(jobTypes, topLevelSupportedJobTypes);
known =
known ||
topLevelSupportedJobTypes.length > 0 ||
source.reason === "ok" ||
Number(source.lastProbeAt || 0) > 0 ||
source.installed === true ||
source.healthy === true;
}
for (const value of [
source.jobs?.supportedTypes,
source.jobs?.builtinTypes,
source.jobs?.registry?.jobTypes,
source.features?.jobs?.supportedTypes,
source.features?.jobs?.builtinTypes,
source.features?.jobs?.registry?.jobTypes,
source.featureDetails?.jobs?.supportedTypes,
source.featureDetails?.jobs?.builtinTypes,
source.featureDetails?.jobs?.registry?.jobTypes,
source.core?.health?.jobRegistrySummary?.jobTypes,
]) {
known = collectJobTypesFromArray(jobTypes, value) || known;
}
for (const value of [
source.jobs?.registry?.entries,
source.features?.jobs?.registry?.entries,
source.featureDetails?.jobs?.registry?.entries,
source.core?.health?.jobRegistrySummary?.entries,
]) {
known = collectJobTypesFromEntries(jobTypes, value) || known;
}
return {
supportedJobTypes: Array.from(jobTypes).sort(),
supportedJobTypesKnown: known,
};
}
export function createDefaultAuthorityCapabilityState(overrides = {}) {
return {
enabledMode: "auto",
@@ -332,6 +401,8 @@ export function createDefaultAuthorityCapabilityState(overrides = {}) {
storagePrimaryReady: false,
triviumPrimaryReady: false,
jobsReady: false,
supportedJobTypes: [],
supportedJobTypesKnown: false,
blobReady: false,
features: [],
missingFeatures: ["sql.query", "sql.mutation", "trivium.search", "jobs", "blob-or-private-files"],
@@ -351,6 +422,7 @@ export function normalizeAuthorityCapabilityState(input = {}, settings = {}) {
const source = input && typeof input === "object" && !Array.isArray(input) ? input : {};
const features = new Set((Array.isArray(source.features) ? source.features : []).map(normalizeFeatureName).filter(Boolean));
const readiness = createFeatureReadiness(features);
const supportedJobs = collectSupportedJobTypes(source);
const missingFeatures = Array.isArray(source.missingFeatures) && source.missingFeatures.length
? source.missingFeatures.map(String)
: collectMissingFeatures(readiness);
@@ -380,6 +452,8 @@ export function normalizeAuthorityCapabilityState(input = {}, settings = {}) {
storagePrimaryReady,
triviumPrimaryReady,
jobsReady,
supportedJobTypes: supportedJobs.supportedJobTypes,
supportedJobTypesKnown: supportedJobs.supportedJobTypesKnown,
blobReady,
features: Array.from(features).sort(),
missingFeatures,
@@ -396,6 +470,7 @@ export function normalizeAuthorityCapabilityState(input = {}, settings = {}) {
export function normalizeAuthorityProbeResponse(payload = {}, context = {}) {
const settings = normalizeAuthoritySettings(context.settings || {});
const features = collectAuthorityFeatures(payload);
const supportedJobs = collectSupportedJobTypes(payload);
const readiness = createFeatureReadiness(features);
const missingFeatures = collectMissingFeatures(readiness);
const sessionReady = payload?.sessionReady ?? payload?.session?.ready ?? payload?.session?.active ?? true;
@@ -408,6 +483,8 @@ export function normalizeAuthorityProbeResponse(payload = {}, context = {}) {
sessionReady: Boolean(sessionReady),
permissionReady: Boolean(permissionReady),
features: Array.from(features),
supportedJobTypes: supportedJobs.supportedJobTypes,
supportedJobTypesKnown: supportedJobs.supportedJobTypesKnown,
missingFeatures,
reason: missingFeatures.length ? "missing-required-features" : "ok",
endpoint: context.endpoint || "",
@@ -519,6 +596,7 @@ export async function probeAuthorityCapabilities(options = {}) {
payload = {};
}
const features = collectAuthorityFeatures(payload);
const supportedJobs = collectSupportedJobTypes(payload);
const readiness = createFeatureReadiness(features);
const missingFeatures = collectMissingFeatures(readiness);
const healthy = payload?.healthy ?? payload?.ok ?? true;
@@ -544,6 +622,8 @@ export async function probeAuthorityCapabilities(options = {}) {
sessionReady: Boolean(sessionReady),
permissionReady: Boolean(permissionReady),
features: Array.from(features),
supportedJobTypes: supportedJobs.supportedJobTypes,
supportedJobTypesKnown: supportedJobs.supportedJobTypesKnown,
missingFeatures,
reason,
lastError: dataPlaneLastError,

View File

@@ -3,7 +3,9 @@ import assert from "node:assert/strict";
import {
buildAuthorityProbeUrls,
collectAuthorityFeatures,
createDefaultAuthorityCapabilityState,
normalizeAuthorityCapabilityState,
normalizeAuthorityProbeResponse,
normalizeAuthoritySettings,
probeAuthorityCapabilities,
} from "../runtime/authority-capabilities.js";
@@ -174,4 +176,132 @@ const relativeUnavailable = await probeAuthorityCapabilities({
assert.equal(relativeUnavailable.reason, "relative-url-unavailable");
assert.equal(relativeUnavailable.serverPrimaryReady, false);
// Regression: Authority capability normalization records explicit supported job types from probe payloads.
// When a probe payload provides jobs.supportedTypes, normalizeAuthorityCapabilityState should surface
// them as supportedJobTypes and set supportedJobTypesKnown = true.
const explicitJobTypesState = normalizeAuthorityCapabilityState(
{
installed: true,
healthy: true,
features: ["sql", "trivium", "jobs", "transfers.fs"],
jobs: { supportedTypes: ["authority.vector.rebuild", "authority.cache.invalidate"] },
},
defaultSettings,
);
assert.equal(explicitJobTypesState.supportedJobTypesKnown, true);
assert.deepEqual(explicitJobTypesState.supportedJobTypes, [
"authority.cache.invalidate",
"authority.vector.rebuild",
]);
// Regression: Current Authority builtin job list is known and excludes authority.vector.rebuild.
// When the probe payload reports a restricted job type list that omits authority.vector.rebuild,
// supportedJobTypes should NOT contain it and supportedJobTypesKnown should be true.
const restrictedJobTypesState = normalizeAuthorityCapabilityState(
{
installed: true,
healthy: true,
features: ["sql", "trivium", "jobs", "transfers.fs"],
jobs: {
builtinTypes: ["delay", "sql.backup", "trivium.flush", "fs.import-jsonl"],
registry: {
jobTypes: ["delay", "sql.backup", "trivium.flush", "fs.import-jsonl"],
entries: [{ type: "delay" }],
},
},
},
defaultSettings,
);
assert.equal(restrictedJobTypesState.supportedJobTypesKnown, true);
assert.equal(
restrictedJobTypesState.supportedJobTypes.includes("authority.vector.rebuild"),
false,
);
const authorityProbeJobTypesState = normalizeAuthorityProbeResponse(
{
healthy: true,
features: {
sql: { queryPage: true },
trivium: { upsert: true },
jobs: {
background: true,
builtinTypes: ["delay", "sql.backup", "trivium.flush", "fs.import-jsonl"],
},
transfers: { fs: true },
},
jobs: {
builtinTypes: ["delay", "sql.backup", "trivium.flush", "fs.import-jsonl"],
registry: {
jobTypes: ["delay", "sql.backup", "trivium.flush", "fs.import-jsonl"],
entries: [{ type: "fs.import-jsonl" }],
},
},
core: {
health: {
jobRegistrySummary: {
jobTypes: ["delay", "sql.backup", "trivium.flush", "fs.import-jsonl"],
entries: [{ type: "trivium.flush" }],
},
},
},
},
{ settings: defaultSettings, nowMs: 4000 },
);
assert.equal(authorityProbeJobTypesState.supportedJobTypesKnown, true);
assert.deepEqual(authorityProbeJobTypesState.supportedJobTypes, [
"delay",
"fs.import-jsonl",
"sql.backup",
"trivium.flush",
]);
assert.equal(
authorityProbeJobTypesState.supportedJobTypes.includes("authority.vector.rebuild"),
false,
);
const renormalizedJobTypesState = normalizeAuthorityCapabilityState(
authorityProbeJobTypesState,
defaultSettings,
);
assert.equal(renormalizedJobTypesState.supportedJobTypesKnown, true);
assert.deepEqual(renormalizedJobTypesState.supportedJobTypes, authorityProbeJobTypesState.supportedJobTypes);
const emptySupportedJobTypesProbeState = normalizeAuthorityProbeResponse(
{
healthy: true,
features: {
sql: { queryPage: true },
trivium: { upsert: true },
jobs: { background: true },
transfers: { fs: true },
},
supportedJobTypes: [],
},
{ settings: defaultSettings, nowMs: 5000 },
);
assert.equal(emptySupportedJobTypesProbeState.supportedJobTypesKnown, true);
assert.deepEqual(emptySupportedJobTypesProbeState.supportedJobTypes, []);
// Regression: Legacy probes with generic jobs.background but no explicit job type list keep
// jobsReady === true and mark job type support as unknown (supportedJobTypesKnown === false).
const legacyProbeState = normalizeAuthorityCapabilityState(
{
installed: true,
healthy: true,
features: ["sql", "trivium", "jobs", "transfers.fs"],
},
defaultSettings,
);
assert.equal(legacyProbeState.jobsReady, true);
assert.equal(legacyProbeState.supportedJobTypesKnown, false);
assert.deepEqual(legacyProbeState.supportedJobTypes, []);
const defaultCapabilityState = normalizeAuthorityCapabilityState(
createDefaultAuthorityCapabilityState(),
defaultSettings,
);
assert.equal(defaultCapabilityState.supportedJobTypesKnown, false);
assert.deepEqual(defaultCapabilityState.supportedJobTypes, []);
console.log("authority-capabilities tests passed");