refactor(types): drain chained-assertion ledger — core (#124351)

This commit is contained in:
Peter Steinberger
2026-08-15 19:41:31 -07:00
committed by GitHub
parent aed4510bd0
commit 6bbc57e526
7 changed files with 89 additions and 51 deletions
+29 -14
View File
@@ -664,22 +664,37 @@ export default {
"extensions/zalo",
"extensions/zalouser",
"packages/ai",
"src/runtime.ts",
"src/acp",
"src/acp/client.ts", // Node and Web ReadableStream types live in separate namespaces.
"src/acp/server.ts", // Node and Web ReadableStream types live in separate namespaces.
"src/agents",
"src/channels",
"src/commands",
"src/config",
"src/gateway",
"src/infra",
"src/media",
"src/channels/plugins/config-schema.ts", // Public SDK Zod generics preserve caller schema identity.
"src/commands/channel-test-registry.ts", // Test support.
"src/commands/doctor/cron/legacy-repair.ts", // Partially validated legacy rows cross the canonical cron store type.
"src/commands/doctor/cron/legacy-store-migration.ts", // Legacy loader carries partial rows in the canonical store envelope.
"src/commands/doctor/cron/warnings.ts", // Doctor inspects partially parsed cron rows.
"src/config/schema.hints.ts", // Zod pipe internals cross its public type namespace.
"src/config/sessions/store-entry-shape.ts", // Legacy projection accepts partially validated session records.
"src/gateway/cli-session-history.claude.ts", // External CLI messages cross the canonical transcript redactor.
"src/gateway/mcp-app-standalone.ts", // Generated standalone browser code bridges the DOM namespace.
"src/gateway/server-methods/chat-transcript-inject.ts", // Gateway media blocks exceed the canonical message content union.
"src/gateway/test-http-response.ts", // Test support.
"src/infra/backup-volatile-stat-cache.ts", // node-tar's cache expects full Stats for a synthetic sentinel.
"src/infra/diagnostic-trace-propagation.ts", // Global symbol registry crosses module copies.
"src/infra/net/runtime-fetch.ts", // Undici and DOM fetch types live in separate namespaces.
"src/infra/state-migrations.meeting-transcripts-files.ts", // Legacy summary validation does not prove element types.
"src/infra/unhandled-rejections.ts", // Global symbol registry crosses module copies.
"src/meeting-bot",
"src/plugin-sdk",
"src/plugins",
"src/process",
"src/proxy-capture",
"src/shared",
"src/trajectory",
"src/plugin-sdk/channel-config-helpers.ts", // Public SDK accessor generics are intentionally decoupled.
"src/plugin-sdk/provider-stream-shared.ts", // Untyped normalizer events need a transport stream API redesign.
"src/plugin-sdk/qa-runtime.ts", // Public SDK lazy module exposes a narrower runtime surface.
"src/plugins/hook-isolation.ts", // Optional WebAssembly globals bridge runtime type namespaces.
"src/plugins/interactive.ts", // Dynamic plugin context keys cross the generic handler seam.
"src/plugins/loader-runtime-load.ts", // Discovery-only runtime is widened by the registry proxy.
"src/plugins/registry-runtime.ts", // Bundled owner wrapper crosses the public inbound generic.
"src/plugins/runtime/index.ts", // Lazy assembly adds required runtime capabilities after construction.
"src/process/exec-spawn.ts", // Rebuilt Execa options cross its result generic.
"src/proxy-capture/store.sqlite.ts", // Implementation preserves overloaded shipped constructor contracts.
"src/trajectory/export.ts", // Legacy migration mutates pre-canonical transcript entries.
"ui/src",
],
}),
+28 -19
View File
@@ -7,6 +7,7 @@
// marks the session dirty for its write or maintenance owner to rebuild from
// the canonical visible-path resolver.
import type { DatabaseSync } from "node:sqlite";
import type { ColumnType } from "kysely";
import {
executeSqliteQuerySync,
executeSqliteQueryTakeFirstSync,
@@ -27,14 +28,24 @@ import {
isSessionTranscriptSideAppendEntry,
parseSessionTranscriptTreeEntry,
} from "./transcript-tree.js";
type TranscriptIndexDatabase = Pick<
OpenClawAgentKyselyDatabase,
| "session_windows"
| "session_transcript_active_events"
| "session_transcript_fts"
| "session_transcript_index_state"
| "transcript_events"
>;
type TranscriptIndexDatabase = Omit<
Pick<
OpenClawAgentKyselyDatabase,
| "session_windows"
| "session_transcript_active_events"
| "session_transcript_fts"
| "session_transcript_index_state"
| "transcript_events"
>,
"session_transcript_fts"
> & {
session_transcript_fts: Omit<
OpenClawAgentKyselyDatabase["session_transcript_fts"],
"timestamp"
> & {
timestamp: ColumnType<string | null, number | string | null, number | string | null>;
};
};
export type SessionTranscriptProjectionState = {
activeEventCount: number;
@@ -158,17 +169,15 @@ function deleteActiveEventRows(db: DatabaseSync, sessionId: string): void {
function insertFtsRow(db: DatabaseSync, sessionId: string, entry: TranscriptIndexEntry): void {
executeSqliteQuerySync(
db,
getIndexKysely(db)
.insertInto("session_transcript_fts")
.values({
text: entry.text,
session_id: sessionId,
message_id: entry.messageId,
role: entry.role,
// FTS5 aux columns are typeless, so codegen types them as string;
// SQLite stores the numeric timestamp natively and readers normalize.
timestamp: entry.timestamp as unknown as string,
}),
getIndexKysely(db).insertInto("session_transcript_fts").values({
text: entry.text,
session_id: sessionId,
message_id: entry.messageId,
role: entry.role,
// FTS5 aux columns are typeless; the local insert type preserves the
// numeric timestamp SQLite stores while generated readers stay strings.
timestamp: entry.timestamp,
}),
);
}
@@ -1,5 +1,5 @@
import type { DatabaseSync } from "node:sqlite";
import type { Generated } from "kysely";
import type { ColumnType, Generated } from "kysely";
import {
executeSqliteQuerySync,
executeSqliteQueryTakeFirstSync,
@@ -23,8 +23,12 @@ type TranscriptProjectionDatabase = Pick<
session_transcript_active_events: OpenClawAgentKyselyDatabase["session_transcript_active_events"] & {
rowid: Generated<number>;
};
session_transcript_fts: OpenClawAgentKyselyDatabase["session_transcript_fts"] & {
session_transcript_fts: Omit<
OpenClawAgentKyselyDatabase["session_transcript_fts"],
"timestamp"
> & {
rowid: Generated<number>;
timestamp: ColumnType<string | null, number | string | null, number | string | null>;
};
};
@@ -419,7 +423,7 @@ export function appendPreparedSessionTranscriptProjectionChunkInTransaction(
role: row.role,
session_id: params.sessionId,
text: row.text,
timestamp: row.timestamp as unknown as string,
timestamp: row.timestamp,
})),
),
);
+4 -3
View File
@@ -31,9 +31,10 @@ export function readRuntimePromptImageFactIndexes(
if (!images?.length) {
return undefined;
}
const factIndexes = (images as unknown as Record<PropertyKey, unknown>)[
RUNTIME_PROMPT_IMAGE_FACT_INDEXES
];
const runtimeImages: readonly object[] & {
[RUNTIME_PROMPT_IMAGE_FACT_INDEXES]?: unknown;
} = images;
const factIndexes = runtimeImages[RUNTIME_PROMPT_IMAGE_FACT_INDEXES];
return Array.isArray(factIndexes) &&
factIndexes.length === images.length &&
factIndexes.every(
+2 -2
View File
@@ -73,10 +73,10 @@ export function getGroupRegistry(): {
groups: Map<string, LaneGroupState>;
groupByLane: Map<string, string>;
} {
const state = getQueueState() as unknown as {
const state: ReturnType<typeof getQueueState> & {
laneGroups?: Map<string, LaneGroupState>;
laneGroupByLane?: Map<string, string>;
};
} = getQueueState();
// Migration: an older singleton (pre-upgrade, inherited via globalThis after
// a SIGUSR1 in-process restart) has neither field. Active counts are derived,
// so a late-initialized registry cannot desynchronize from lane state.
+1 -1
View File
@@ -31,7 +31,7 @@ function shouldEmitRuntimeLog(env: NodeJS.ProcessEnv = process.env): boolean {
if (env.OPENCLAW_TEST_RUNTIME_LOG === "1") {
return true;
}
const maybeMockedLog = console.log as unknown as { mock?: unknown };
const maybeMockedLog = console.log as typeof console.log & { mock?: unknown };
return typeof maybeMockedLog.mock === "object";
}
+18 -9
View File
@@ -15,6 +15,7 @@ type LocalRefResolution =
resourceBaseId: string | undefined;
}
| { found: false };
type JsonSchemaNode = JsonSchemaValue | JsonSchemaNode[];
const schemaResourceIds = new WeakMap<object, number>();
let nextSchemaResourceId = 1;
const schemaMapKeywords = new Set([
@@ -670,18 +671,26 @@ function inlineLocalRefsForMatch(
root: JsonSchemaValue,
resourceRoot: JsonSchemaValue,
resourceBaseId: string | undefined,
resolvingRefs?: Set<string>,
): JsonSchemaValue;
function inlineLocalRefsForMatch(
schema: JsonSchemaNode,
root: JsonSchemaValue,
resourceRoot: JsonSchemaValue,
resourceBaseId: string | undefined,
resolvingRefs?: Set<string>,
): JsonSchemaNode;
function inlineLocalRefsForMatch(
schema: JsonSchemaNode,
root: JsonSchemaValue,
resourceRoot: JsonSchemaValue,
resourceBaseId: string | undefined,
resolvingRefs = new Set<string>(),
): JsonSchemaValue {
): JsonSchemaNode {
if (Array.isArray(schema)) {
return schema.map((entry) =>
inlineLocalRefsForMatch(
entry as JsonSchemaValue,
root,
resourceRoot,
resourceBaseId,
resolvingRefs,
),
) as unknown as JsonSchemaValue;
inlineLocalRefsForMatch(entry, root, resourceRoot, resourceBaseId, resolvingRefs),
);
}
if (!isRecord(schema)) {
return schema;