## Summary Wave 17 organizes Fusion into **domain folders** (stacks on #2397). ### Layout - **core/types/** — board, task, agents, settings, merge, workflow, mesh, … - **core/src/** — agents, ai, async-stores, workflows, tasks, config, db, … - **dashboard/app/api/** — client, tasks, agents, git, missions, planning, … - **engine/src/** — agents, auth, execution, merge, missions, overseer, worktree, … Root keepers retained for large entrypoints (`store.ts`, `executor.ts`, `merger.ts`, …). Public barrels (`@fusion/core`, `@fusion/engine`, `app/api.ts` → legacy) stay stable. ## Test plan - [x] `@fusion/core` typecheck - [x] `@fusion/engine` typecheck (pre-existing playwright-core noise only) - [ ] CI merge gate **Stack:** #2394 → #2397 → **this PR**
79 lines
3.1 KiB
TypeScript
79 lines
3.1 KiB
TypeScript
/**
|
|
* Task commit-association persistence (domain module).
|
|
*
|
|
* FNXC:StoreModularization 2026-06-25-00:00:
|
|
* Extracted from the monolithic packages/core/src/store.ts as a pure
|
|
* behavior-preserving refactor. Each function receives the TaskStore
|
|
* instance as its first parameter and performs byte-identical work.
|
|
*
|
|
* FNXC:CodeOrganization 2026-07-15-00:00:
|
|
* Renamed from remaining-ops-9 to a domain name; no behavior change.
|
|
*/
|
|
|
|
import { TaskStore } from "../store.js";
|
|
import { normalizeTaskCommitAssociation } from "../tasks/task-lineage.js";
|
|
import { TaskCommitAssociationRow } from "./row-types.js";
|
|
import { TaskCommitAssociation } from "../types.js";
|
|
import { and, desc, eq, inArray } from "drizzle-orm";
|
|
import * as schema from "../postgres/schema/index.js";
|
|
|
|
export async function getTaskCommitAssociationsByLineageIdImpl(store: TaskStore, lineageId: string): Promise<TaskCommitAssociation[]> {
|
|
/*
|
|
FNXC:PostgresCutover 2026-07-04:
|
|
Backend-mode read of task_commit_associations by lineage id via async
|
|
Drizzle. Mirrors the SQLite ORDER BY authoredAt DESC, createdAt DESC. The
|
|
Drizzle select returns camelCase columns (schema-mapped), cast to the
|
|
shared TaskCommitAssociationRow shape used by normalizeTaskCommitAssociation.
|
|
*/
|
|
const layer = store.asyncLayer!;
|
|
const rows = await layer.db
|
|
.select()
|
|
.from(schema.project.taskCommitAssociations)
|
|
.where(eq(schema.project.taskCommitAssociations.taskLineageId, lineageId))
|
|
.orderBy(
|
|
desc(schema.project.taskCommitAssociations.authoredAt),
|
|
desc(schema.project.taskCommitAssociations.createdAt),
|
|
);
|
|
return (rows as TaskCommitAssociationRow[]).map((row) =>
|
|
normalizeTaskCommitAssociation({
|
|
...row,
|
|
note: row.note ?? undefined,
|
|
additions: row.additions ?? undefined,
|
|
deletions: row.deletions ?? undefined,
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function replaceLegacyTaskCommitAssociationsImpl(store: TaskStore,
|
|
lineageId: string,
|
|
associations: Array<Omit<TaskCommitAssociation, "id" | "createdAt" | "updatedAt" | "taskLineageId">>,
|
|
): Promise<void> {
|
|
/*
|
|
FNXC:PostgresCutover 2026-07-04:
|
|
Backend-mode replacement of legacy-matched task_commit_associations: delete
|
|
the legacy-/manual-matched rows for the lineage via async Drizzle, then
|
|
re-insert through store.upsertTaskCommitAssociation (which itself dispatches
|
|
to the async upsert in backend mode). Canonical-lineage-trailer rows are
|
|
preserved (matched only on the three legacy sources), matching the SQLite
|
|
path's IN-filter exactly.
|
|
*/
|
|
const layer = store.asyncLayer!;
|
|
await layer.db
|
|
.delete(schema.project.taskCommitAssociations)
|
|
.where(
|
|
and(
|
|
eq(schema.project.taskCommitAssociations.taskLineageId, lineageId),
|
|
inArray(schema.project.taskCommitAssociations.matchedBy, [
|
|
"legacy-task-id-trailer",
|
|
"legacy-subject",
|
|
"manual-reconciliation",
|
|
]),
|
|
),
|
|
);
|
|
for (const association of associations) {
|
|
await store.upsertTaskCommitAssociation({ ...association, taskLineageId: lineageId });
|
|
}
|
|
return;
|
|
}
|
|
|