mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
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:
@@ -33,6 +33,10 @@ function normalizeFeatureName(value) {
|
|||||||
return String(value ?? "").trim().toLowerCase();
|
return String(value ?? "").trim().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeJobType(value) {
|
||||||
|
return String(value ?? "").trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
function addFeature(features, value) {
|
function addFeature(features, value) {
|
||||||
const normalized = normalizeFeatureName(value);
|
const normalized = normalizeFeatureName(value);
|
||||||
if (normalized) features.add(normalized);
|
if (normalized) features.add(normalized);
|
||||||
@@ -319,6 +323,71 @@ export function collectAuthorityFeatures(payload = {}) {
|
|||||||
return features;
|
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 = {}) {
|
export function createDefaultAuthorityCapabilityState(overrides = {}) {
|
||||||
return {
|
return {
|
||||||
enabledMode: "auto",
|
enabledMode: "auto",
|
||||||
@@ -332,6 +401,8 @@ export function createDefaultAuthorityCapabilityState(overrides = {}) {
|
|||||||
storagePrimaryReady: false,
|
storagePrimaryReady: false,
|
||||||
triviumPrimaryReady: false,
|
triviumPrimaryReady: false,
|
||||||
jobsReady: false,
|
jobsReady: false,
|
||||||
|
supportedJobTypes: [],
|
||||||
|
supportedJobTypesKnown: false,
|
||||||
blobReady: false,
|
blobReady: false,
|
||||||
features: [],
|
features: [],
|
||||||
missingFeatures: ["sql.query", "sql.mutation", "trivium.search", "jobs", "blob-or-private-files"],
|
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 source = input && typeof input === "object" && !Array.isArray(input) ? input : {};
|
||||||
const features = new Set((Array.isArray(source.features) ? source.features : []).map(normalizeFeatureName).filter(Boolean));
|
const features = new Set((Array.isArray(source.features) ? source.features : []).map(normalizeFeatureName).filter(Boolean));
|
||||||
const readiness = createFeatureReadiness(features);
|
const readiness = createFeatureReadiness(features);
|
||||||
|
const supportedJobs = collectSupportedJobTypes(source);
|
||||||
const missingFeatures = Array.isArray(source.missingFeatures) && source.missingFeatures.length
|
const missingFeatures = Array.isArray(source.missingFeatures) && source.missingFeatures.length
|
||||||
? source.missingFeatures.map(String)
|
? source.missingFeatures.map(String)
|
||||||
: collectMissingFeatures(readiness);
|
: collectMissingFeatures(readiness);
|
||||||
@@ -380,6 +452,8 @@ export function normalizeAuthorityCapabilityState(input = {}, settings = {}) {
|
|||||||
storagePrimaryReady,
|
storagePrimaryReady,
|
||||||
triviumPrimaryReady,
|
triviumPrimaryReady,
|
||||||
jobsReady,
|
jobsReady,
|
||||||
|
supportedJobTypes: supportedJobs.supportedJobTypes,
|
||||||
|
supportedJobTypesKnown: supportedJobs.supportedJobTypesKnown,
|
||||||
blobReady,
|
blobReady,
|
||||||
features: Array.from(features).sort(),
|
features: Array.from(features).sort(),
|
||||||
missingFeatures,
|
missingFeatures,
|
||||||
@@ -396,6 +470,7 @@ export function normalizeAuthorityCapabilityState(input = {}, settings = {}) {
|
|||||||
export function normalizeAuthorityProbeResponse(payload = {}, context = {}) {
|
export function normalizeAuthorityProbeResponse(payload = {}, context = {}) {
|
||||||
const settings = normalizeAuthoritySettings(context.settings || {});
|
const settings = normalizeAuthoritySettings(context.settings || {});
|
||||||
const features = collectAuthorityFeatures(payload);
|
const features = collectAuthorityFeatures(payload);
|
||||||
|
const supportedJobs = collectSupportedJobTypes(payload);
|
||||||
const readiness = createFeatureReadiness(features);
|
const readiness = createFeatureReadiness(features);
|
||||||
const missingFeatures = collectMissingFeatures(readiness);
|
const missingFeatures = collectMissingFeatures(readiness);
|
||||||
const sessionReady = payload?.sessionReady ?? payload?.session?.ready ?? payload?.session?.active ?? true;
|
const sessionReady = payload?.sessionReady ?? payload?.session?.ready ?? payload?.session?.active ?? true;
|
||||||
@@ -408,6 +483,8 @@ export function normalizeAuthorityProbeResponse(payload = {}, context = {}) {
|
|||||||
sessionReady: Boolean(sessionReady),
|
sessionReady: Boolean(sessionReady),
|
||||||
permissionReady: Boolean(permissionReady),
|
permissionReady: Boolean(permissionReady),
|
||||||
features: Array.from(features),
|
features: Array.from(features),
|
||||||
|
supportedJobTypes: supportedJobs.supportedJobTypes,
|
||||||
|
supportedJobTypesKnown: supportedJobs.supportedJobTypesKnown,
|
||||||
missingFeatures,
|
missingFeatures,
|
||||||
reason: missingFeatures.length ? "missing-required-features" : "ok",
|
reason: missingFeatures.length ? "missing-required-features" : "ok",
|
||||||
endpoint: context.endpoint || "",
|
endpoint: context.endpoint || "",
|
||||||
@@ -519,6 +596,7 @@ export async function probeAuthorityCapabilities(options = {}) {
|
|||||||
payload = {};
|
payload = {};
|
||||||
}
|
}
|
||||||
const features = collectAuthorityFeatures(payload);
|
const features = collectAuthorityFeatures(payload);
|
||||||
|
const supportedJobs = collectSupportedJobTypes(payload);
|
||||||
const readiness = createFeatureReadiness(features);
|
const readiness = createFeatureReadiness(features);
|
||||||
const missingFeatures = collectMissingFeatures(readiness);
|
const missingFeatures = collectMissingFeatures(readiness);
|
||||||
const healthy = payload?.healthy ?? payload?.ok ?? true;
|
const healthy = payload?.healthy ?? payload?.ok ?? true;
|
||||||
@@ -544,6 +622,8 @@ export async function probeAuthorityCapabilities(options = {}) {
|
|||||||
sessionReady: Boolean(sessionReady),
|
sessionReady: Boolean(sessionReady),
|
||||||
permissionReady: Boolean(permissionReady),
|
permissionReady: Boolean(permissionReady),
|
||||||
features: Array.from(features),
|
features: Array.from(features),
|
||||||
|
supportedJobTypes: supportedJobs.supportedJobTypes,
|
||||||
|
supportedJobTypesKnown: supportedJobs.supportedJobTypesKnown,
|
||||||
missingFeatures,
|
missingFeatures,
|
||||||
reason,
|
reason,
|
||||||
lastError: dataPlaneLastError,
|
lastError: dataPlaneLastError,
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import assert from "node:assert/strict";
|
|||||||
import {
|
import {
|
||||||
buildAuthorityProbeUrls,
|
buildAuthorityProbeUrls,
|
||||||
collectAuthorityFeatures,
|
collectAuthorityFeatures,
|
||||||
|
createDefaultAuthorityCapabilityState,
|
||||||
normalizeAuthorityCapabilityState,
|
normalizeAuthorityCapabilityState,
|
||||||
|
normalizeAuthorityProbeResponse,
|
||||||
normalizeAuthoritySettings,
|
normalizeAuthoritySettings,
|
||||||
probeAuthorityCapabilities,
|
probeAuthorityCapabilities,
|
||||||
} from "../runtime/authority-capabilities.js";
|
} from "../runtime/authority-capabilities.js";
|
||||||
@@ -174,4 +176,132 @@ const relativeUnavailable = await probeAuthorityCapabilities({
|
|||||||
assert.equal(relativeUnavailable.reason, "relative-url-unavailable");
|
assert.equal(relativeUnavailable.reason, "relative-url-unavailable");
|
||||||
assert.equal(relativeUnavailable.serverPrimaryReady, false);
|
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");
|
console.log("authority-capabilities tests passed");
|
||||||
|
|||||||
Reference in New Issue
Block a user