Iostream-Li's picture
Add files using upload-large-folder tool
ff78003 verified
Raw
History Blame Contribute Delete
3.48 kB
/**
* Task #242 (B1) — Capability data-foundation 骨架接口。
*
* **本任务**:只接口 + 一个最小实现(`writeRow` 真插表 / `readRows` 真查表),
* 让 B7 可以平滑加 distill / reuse 路径。
* **B7**:真把 inner-loop run 蒸馏成 row(parameter-fingerprint / failure-mode / ...)
* 并在 inner-loop search 步骤复用。
*
* 注意:`capability_data_foundation` 表已在 B2 (#255) 建好;本模块直接
* 复用,不新建 schema。
*/
import { and, desc, eq } from "drizzle-orm";
import {
db,
capabilityDataFoundation,
type CapabilityDataFoundationRow,
type InsertCapabilityDataFoundationRow,
} from "@workspace/db";
import { newId } from "../../ids.js";
export interface DataFoundationRow {
id: string;
capabilityId: string;
kind: string;
payload: Record<string, unknown>;
sourceRunId: string | null;
createdAt: Date;
}
export interface WriteRowInput {
capabilityId: string;
kind: string;
payload: Record<string, unknown>;
sourceRunId?: string | null;
}
export interface ReadRowsQuery {
capabilityId: string;
kind?: string;
/** Default 50, max 500. */
limit?: number;
/**
* **Anti-self-loop**: when set, EXCLUDE rows where capabilityId matches
* the requester (B7 will set this when an inner-loop search step asks
* for "what other capabilities have learned" without polluting itself).
*/
excludeSelf?: boolean;
}
function rowToOutput(r: CapabilityDataFoundationRow): DataFoundationRow {
return {
id: r.id,
capabilityId: r.capabilityId,
kind: r.kind,
payload: (r.payload ?? {}) as Record<string, unknown>,
sourceRunId: r.sourceRunId,
createdAt: r.createdAt,
};
}
export async function writeRow(input: WriteRowInput): Promise<{ id: string }> {
if (!input.capabilityId) {
throw new Error("data-foundation/writeRow: capabilityId required");
}
if (!input.kind) {
throw new Error("data-foundation/writeRow: kind required");
}
const id = newId("cdf");
const row: InsertCapabilityDataFoundationRow = {
id,
capabilityId: input.capabilityId,
kind: input.kind,
payload: input.payload,
sourceRunId: input.sourceRunId ?? null,
};
await db.insert(capabilityDataFoundation).values(row);
return { id };
}
export async function readRows(
query: ReadRowsQuery,
): Promise<DataFoundationRow[]> {
const limit = Math.min(Math.max(query.limit ?? 50, 1), 500);
const conds = [];
if (query.excludeSelf) {
// 反模式:excludeSelf + capabilityId 同时给:本意是"排除自己读自己的行"
// 但 capabilityId 是必填,所以这里其实排除其它 capability 的行=空集。
// 真正的"排除调用方自己"在 B7 inner-loop search 里实现(用 NOT 等),
// 本骨架只 throw 提示调用方语义不对。
throw new Error(
"data-foundation/readRows: excludeSelf is reserved for B7 inner-loop search " +
"and is not yet implemented; pass capabilityId only to read own rows.",
);
}
if (query.kind) {
conds.push(
and(
eq(capabilityDataFoundation.capabilityId, query.capabilityId),
eq(capabilityDataFoundation.kind, query.kind),
),
);
} else {
conds.push(eq(capabilityDataFoundation.capabilityId, query.capabilityId));
}
const rows = await db
.select()
.from(capabilityDataFoundation)
.where(conds[0])
.orderBy(desc(capabilityDataFoundation.createdAt))
.limit(limit);
return rows.map(rowToOutput);
}