fix: reuse proven runtime readiness for workbench reads
This commit is contained in:
@@ -27,6 +27,7 @@ export function createWorkbenchFactsStore(options = {}, actor = null) {
|
||||
persistence: result?.persistence ?? null
|
||||
};
|
||||
} catch (error) {
|
||||
logWorkbenchFactsQueryFailure(options.logger ?? console, params, error);
|
||||
return {
|
||||
facts: emptyWorkbenchFacts(),
|
||||
count: 0,
|
||||
@@ -137,6 +138,26 @@ export function createWorkbenchFactsStore(options = {}, actor = null) {
|
||||
};
|
||||
}
|
||||
|
||||
function logWorkbenchFactsQueryFailure(logger, params = {}, error = null) {
|
||||
const families = Array.isArray(params.families) ? params.families : [];
|
||||
const event = {
|
||||
event: "workbench_facts_query_failed",
|
||||
ok: false,
|
||||
families,
|
||||
hasSessionId: Boolean(params.sessionId),
|
||||
hasTraceId: Boolean(params.traceId),
|
||||
hasOwnerUserId: Boolean(params.ownerUserId),
|
||||
errorName: error?.name ?? "Error",
|
||||
errorCode: error?.code ?? null,
|
||||
message: error instanceof Error ? error.message : String(error ?? "unknown"),
|
||||
valuesRedacted: true
|
||||
};
|
||||
try {
|
||||
if (typeof logger?.warn === "function") logger.warn(JSON.stringify(event));
|
||||
else if (typeof logger?.log === "function") logger.log(JSON.stringify(event));
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function durableTraceSnapshot(runtimeStore, traceId) {
|
||||
if (!runtimeStore || typeof runtimeStore.queryAgentTraceEvents !== "function") return null;
|
||||
const safeId = safeTraceId(traceId);
|
||||
|
||||
@@ -806,6 +806,33 @@ test("configured postgres runtime persists and queries Workbench durable facts",
|
||||
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("SELECT session_json FROM workbench_sessions WHERE session_id = $1")));
|
||||
});
|
||||
|
||||
test("configured postgres runtime reuses proven readiness for Workbench durable reads", async () => {
|
||||
const queryClient = createFakePostgresClient({ migrationReady: true });
|
||||
const store = createConfiguredCloudRuntimeStore({
|
||||
env: {
|
||||
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
|
||||
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
|
||||
},
|
||||
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
|
||||
queryClient,
|
||||
now: () => "2026-06-20T10:00:00.000Z"
|
||||
});
|
||||
await store.writeWorkbenchFacts({
|
||||
facts: {
|
||||
sessions: [{ sessionId: "ses_ready_cached", ownerUserId: "usr_ready", status: "running", updatedAt: "2026-06-20T10:00:01.000Z" }]
|
||||
}
|
||||
});
|
||||
queryClient.calls.length = 0;
|
||||
|
||||
const first = await store.queryWorkbenchFacts({ families: ["sessions"], limit: 10 });
|
||||
const second = await store.queryWorkbenchFacts({ families: ["sessions"], limit: 10 });
|
||||
|
||||
assert.equal(first.count, 1);
|
||||
assert.equal(second.count, 1);
|
||||
assert.equal(queryClient.calls.filter((call) => isReadinessQuery(call.sql)).length, 0);
|
||||
assert.equal(queryClient.calls.filter((call) => call.sql.startsWith("SELECT session_json FROM workbench_sessions")).length, 2);
|
||||
});
|
||||
|
||||
test("configured postgres runtime queries requested workbench fact families concurrently", async () => {
|
||||
const expectedReads = 4;
|
||||
let started = 0;
|
||||
@@ -930,6 +957,12 @@ test("configured postgres runtime pushes trace event query filters into SQL", as
|
||||
assert.deepEqual(select.params, ["ses_filter_b"]);
|
||||
});
|
||||
|
||||
function isReadinessQuery(sql) {
|
||||
return sql.includes("information_schema.columns")
|
||||
|| sql.startsWith("SELECT id, schema_version FROM hwlab_schema_migrations")
|
||||
|| sql.startsWith("SELECT COUNT(*)::int AS count FROM ");
|
||||
}
|
||||
|
||||
function createFakePostgresClient({
|
||||
migrationReady = true,
|
||||
migrationErrorCode = null,
|
||||
|
||||
@@ -1372,7 +1372,10 @@ export class PostgresCloudRuntimeStore {
|
||||
}
|
||||
|
||||
async assertReadyForDurableReads(method) {
|
||||
const current = this.summary();
|
||||
if (isReadyForDurableRuntimeRead(current)) return;
|
||||
const readiness = await this.readiness();
|
||||
if (isReadyForDurableRuntimeRead(readiness)) return;
|
||||
if (readiness.ready !== true || readiness.durable !== true || readiness.liveRuntimeEvidence !== true) {
|
||||
throw durableRuntimeReadBlockedError(method, readiness);
|
||||
}
|
||||
@@ -1697,6 +1700,10 @@ export class PostgresCloudRuntimeStore {
|
||||
}
|
||||
}
|
||||
|
||||
function isReadyForDurableRuntimeRead(readiness = {}) {
|
||||
return readiness.ready === true && readiness.durable === true && readiness.liveRuntimeEvidence === true;
|
||||
}
|
||||
|
||||
function normalizeCapabilityInputs(params) {
|
||||
const value = params.capabilities ?? params.capability ?? params;
|
||||
if (Array.isArray(value)) {
|
||||
|
||||
Reference in New Issue
Block a user